# HG changeset patch
# Node ID 25b85266191e
# Parent  854601fc7f0b
diff --git a/libpurple/core.c b/libpurple/core.c
--- a/libpurple/core.c
+++ b/libpurple/core.c
@@ -234,7 +234,6 @@
 	purple_plugins_uninit();
 
 	/* after plugins */
-	purple_media_manager_shutdown();
 	purple_contact_manager_shutdown();
 	purple_account_manager_shutdown();
 	purple_credential_manager_shutdown();
diff --git a/libpurple/media-gst.h b/libpurple/media-gst.h
deleted file mode 100644
--- a/libpurple/media-gst.h
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_MEDIA_GST_H
-#define PURPLE_MEDIA_GST_H
-
-#include "media.h"
-#include "mediamanager.h"
-#include "purpleversion.h"
-
-#include <gst/gst.h>
-
-#define PURPLE_TYPE_MEDIA_ELEMENT_TYPE  purple_media_element_type_get_type()
-
-#define PURPLE_TYPE_MEDIA_ELEMENT_INFO  purple_media_element_info_get_type()
-
-/**
- * PurpleMediaElementInfo:
- *
- * An opaque structure representing an audio/video source/sink.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_TYPE_IN_2_6
-typedef struct _PurpleMediaElementInfo PurpleMediaElementInfo;
-
-/**
- * PurpleMediaElementCreateCallback:
- * @info: The element.
- * @media: The media.
- * @session_id: The session id.
- * @participant: The participant.
- *
- * A callback that creates a GstElement for the given parameters.
- *
- * Returns: (transfer full): The new element.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_TYPE_IN_2_6
-typedef GstElement *(*PurpleMediaElementCreateCallback)(
-		PurpleMediaElementInfo *info, PurpleMedia *media,
-		const gchar *session_id, const gchar *participant);
-
-/**
- * PurpleMediaElementType:
- * @PURPLE_MEDIA_ELEMENT_NONE:         empty element
- * @PURPLE_MEDIA_ELEMENT_AUDIO:        supports audio
- * @PURPLE_MEDIA_ELEMENT_VIDEO:        supports video
- * @PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO:  supports audio and video
- * @PURPLE_MEDIA_ELEMENT_NO_SRCS:      has no src pads
- * @PURPLE_MEDIA_ELEMENT_ONE_SRC:      has one src pad
- * @PURPLE_MEDIA_ELEMENT_MULTI_SRC:    has multiple src pads
- * @PURPLE_MEDIA_ELEMENT_REQUEST_SRC:  src pads must be requested
- * @PURPLE_MEDIA_ELEMENT_NO_SINKS:     has no sink pads
- * @PURPLE_MEDIA_ELEMENT_ONE_SINK:     has one sink pad
- * @PURPLE_MEDIA_ELEMENT_MULTI_SINK:   has multiple sink pads
- * @PURPLE_MEDIA_ELEMENT_REQUEST_SINK: sink pads must be requested
- * @PURPLE_MEDIA_ELEMENT_UNIQUE:       This element is unique and only one
- *                                     instance of it should be created at a
- *                                     time
- * @PURPLE_MEDIA_ELEMENT_SRC:          can be set as an active src
- * @PURPLE_MEDIA_ELEMENT_SINK:         can be set as an active sink
- * @PURPLE_MEDIA_ELEMENT_APPLICATION:  supports application data
- *
- * The possible types of media elements.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_TYPE_IN_2_6
-typedef enum {
-	PURPLE_MEDIA_ELEMENT_NONE = 0,
-	PURPLE_MEDIA_ELEMENT_AUDIO = 1,
-	PURPLE_MEDIA_ELEMENT_VIDEO = 1 << 1,
-	PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO = PURPLE_MEDIA_ELEMENT_AUDIO
-			| PURPLE_MEDIA_ELEMENT_VIDEO,
-	PURPLE_MEDIA_ELEMENT_NO_SRCS = 0,
-	PURPLE_MEDIA_ELEMENT_ONE_SRC = 1 << 2,
-	PURPLE_MEDIA_ELEMENT_MULTI_SRC = 1 << 3,
-	PURPLE_MEDIA_ELEMENT_REQUEST_SRC = 1 << 4,
-	PURPLE_MEDIA_ELEMENT_NO_SINKS = 0,
-	PURPLE_MEDIA_ELEMENT_ONE_SINK = 1 << 5,
-	PURPLE_MEDIA_ELEMENT_MULTI_SINK = 1 << 6,
-	PURPLE_MEDIA_ELEMENT_REQUEST_SINK = 1 << 7,
-	PURPLE_MEDIA_ELEMENT_UNIQUE = 1 << 8,
-	PURPLE_MEDIA_ELEMENT_SRC = 1 << 9,
-	PURPLE_MEDIA_ELEMENT_SINK = 1 << 10,
-	PURPLE_MEDIA_ELEMENT_APPLICATION = 1 << 11,
-} PurpleMediaElementType;
-
-G_BEGIN_DECLS
-
-PURPLE_AVAILABLE_IN_2_6
-GType purple_media_element_type_get_type(void);
-
-PURPLE_AVAILABLE_IN_2_6
-G_DECLARE_FINAL_TYPE(PurpleMediaElementInfo, purple_media_element_info, PURPLE,
-		MEDIA_ELEMENT_INFO, GObject)
-
-/**
- * purple_media_get_src:
- * @media: The media object the session is in.
- * @sess_id: The session id of the session to get the source from.
- *
- * Gets the source from a session
- *
- * Returns: (transfer none): The source retrieved.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GstElement *purple_media_get_src(PurpleMedia *media, const gchar *sess_id);
-
-/**
- * purple_media_get_tee:
- * @media: The instance to get the tee from.
- * @session_id: The id of the session to get the tee from.
- * @participant: Optionally, the participant of the stream to get the tee from.
- *
- * Gets the tee from a given session/stream.
- *
- * Returns: (transfer none): The GstTee element from the chosen session/stream.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GstElement *purple_media_get_tee(PurpleMedia *media,
-		const gchar *session_id, const gchar *participant);
-
-
-/**
- * purple_media_manager_get_pipeline:
- * @manager: The media manager to get the pipeline from.
- *
- * Gets the pipeline from the media manager.
- *
- * Returns: (transfer none): The pipeline.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GstElement *purple_media_manager_get_pipeline(PurpleMediaManager *manager);
-
-/**
- * purple_media_manager_get_element:
- * @manager: The media manager to use to obtain the source/sink.
- * @type: The type of source/sink to get.
- * @media: The media call this element is requested for.
- * @session_id: The id of the session this element is requested for or NULL.
- * @participant: The remote user this element is requested for or NULL.
- *
- * Gets the media element for the given session.
- *
- * Returns: (transfer full): A GStreamer source or sink for audio or video.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GstElement *purple_media_manager_get_element(PurpleMediaManager *manager,
-		PurpleMediaSessionType type, PurpleMedia *media,
-		const gchar *session_id, const gchar *participant);
-
-/**
- * purple_media_manager_enumerate_elements:
- * @manager: The media manager to use to obtain the element infos.
- * @type: The type of element infos to get.
- *
- * Enumerates the elements in @manager filtered by @type.
- *
- * Returns: (transfer container) (element-type PurpleMediaElementInfo): A #GList of registered #PurpleMediaElementInfo instances that match
- * @type.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GList *purple_media_manager_enumerate_elements(PurpleMediaManager *manager, PurpleMediaElementType type);
-
-/**
- * purple_media_manager_get_element_info:
- * @manager: The #PurpleMediaManager instance
- * @name: The name of the element to get.
- *
- * Gets the element info for the element named @name in @manager.
- *
- * Returns: (transfer full): The #PurpleMediaElementInfo for @name or NULL.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMediaElementInfo *purple_media_manager_get_element_info(
-		PurpleMediaManager *manager, const gchar *name);
-
-/**
- * purple_media_manager_register_element:
- * @manager: The instance.
- * @info: THe new element to register.
- *
- * Registers @info with @manager.
- *
- * Returns: %TRUE if successful, otherwise %FALSE.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_manager_register_element(PurpleMediaManager *manager,
-		PurpleMediaElementInfo *info);
-
-/**
- * purple_media_manager_unregister_element:
- * @manager: The instance.
- * @name: The name of the element to unregister.
- *
- * Unregisters the elemented named @name from @manager.
- *
- * Returns: %TRUE if the element was found and removed, otherwise %FALSE.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_manager_unregister_element(PurpleMediaManager *manager,
-		const gchar *name);
-
-/**
- * purple_media_manager_set_active_element:
- * @manager: The instance.
- * @info: The new element to activate.
- *
- * Attempts to activate @info as the active element.
- *
- * Returns: %TRUE if successful, otherwise %FALSE.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_manager_set_active_element(PurpleMediaManager *manager,
-		PurpleMediaElementInfo *info);
-
-/**
- * purple_media_manager_get_active_element:
- * @manager: The #PurpleMediaManager instance
- * @type: The #PurpleMediaElementType who's info to get
- *
- * Gets the element that is currently active.
- *
- * Returns: (transfer none): The #PurpleMediaElementInfo for @type.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMediaElementInfo *purple_media_manager_get_active_element(
-		PurpleMediaManager *manager, PurpleMediaElementType type);
-
-/**
- * purple_media_manager_set_video_caps:
- * @manager: The media manager to set the media formats.
- * @caps: Set of allowed media formats.
- *
- * Reduces media formats supported by the video source to given set.
- *
- * Useful to force negotiation of smaller picture resolution more suitable for
- * use with particular codec and communication protocol without rescaling.
- *
- * Since: 2.8
- */
-PURPLE_AVAILABLE_IN_2_8
-void purple_media_manager_set_video_caps(PurpleMediaManager *manager,
-		GstCaps *caps);
-
-/**
- * purple_media_manager_get_video_caps:
- * @manager: The media manager to get the media formats from.
- *
- * Returns current set of media formats limiting the output from video source.
- *
- * Returns: GstCaps limiting the video source's formats.
- *
- * Since: 2.8
- */
-PURPLE_AVAILABLE_IN_2_8
-GstCaps *purple_media_manager_get_video_caps(PurpleMediaManager *manager);
-
-/**
- * purple_media_element_info_get_id:
- * @info: The instance.
- *
- * Gets the identifier from @info.
- *
- * Returns: The identifier.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gchar *purple_media_element_info_get_id(PurpleMediaElementInfo *info);
-
-/**
- * purple_media_element_info_get_name:
- * @info: The instance.
- *
- * Gets the name of @info.
- *
- * Returns: The name of @info.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gchar *purple_media_element_info_get_name(PurpleMediaElementInfo *info);
-
-/**
- * purple_media_element_info_get_element_type:
- * @info: The instance.
- *
- * Gets the element type of @info.
- *
- * Returns: The element type.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMediaElementType purple_media_element_info_get_element_type(
-		PurpleMediaElementInfo *info);
-
-/**
- * purple_media_element_info_call_create:
- * @info: The #PurpleMediaElementInfo to create the element from
- * @media: The media instance.
- * @session_id: The session id.
- * @participant: The participant.
- *
- * Creates a new call.
- *
- * Returns: (transfer full): The new GstElement.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GstElement *purple_media_element_info_call_create(
-		PurpleMediaElementInfo *info, PurpleMedia *media,
-		const gchar *session_id, const gchar *participant);
-
-G_END_DECLS
-
-#endif /* PURPLE_MEDIA_GST_H */
diff --git a/libpurple/media.h b/libpurple/media.h
deleted file mode 100644
--- a/libpurple/media.h
+++ /dev/null
@@ -1,633 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_MEDIA_H
-#define PURPLE_MEDIA_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-typedef struct _PurpleMedia PurpleMedia;
-
-#include "media/candidate.h"
-#include "media/codec.h"
-#include "media/enum-types.h"
-
-#define PURPLE_TYPE_MEDIA            (purple_media_get_type())
-#define PURPLE_MEDIA(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA, PurpleMedia))
-#define PURPLE_MEDIA_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEDIA, PurpleMediaClass))
-#define PURPLE_IS_MEDIA(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEDIA))
-#define PURPLE_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA))
-#define PURPLE_MEDIA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA, PurpleMediaClass))
-
-#include "purpleaccount.h"
-#include "purpleversion.h"
-#include "signals.h"
-#include "util.h"
-
-typedef struct _PurpleMediaClass    PurpleMediaClass;
-typedef struct _PurpleMediaPrivate  PurpleMediaPrivate;
-
-/**
- * PurpleMedia:
- *
- * The media instance
- */
-struct _PurpleMedia
-{
-	GObject parent;
-
-	/*< private >*/
-	PurpleMediaPrivate *priv;
-};
-
-/**
- * PurpleMediaClass:
- *
- * The media class
- */
-struct _PurpleMediaClass
-{
-	GObjectClass parent_class;
-
-	/*< private >*/
-	void (*purple_reserved1)(void);
-	void (*purple_reserved2)(void);
-	void (*purple_reserved3)(void);
-	void (*purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-/**
- * purple_media_get_type:
- *
- * Gets the media class's GType
- *
- * Returns: The media class's GType.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GType purple_media_get_type(void);
-
-/**
- * purple_media_get_session_ids:
- * @media: The media session from which to retrieve session IDs.
- *
- * Gets a list of session IDs.
- *
- * Returns: (element-type utf8) (transfer container): List of session IDs.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GList *purple_media_get_session_ids(PurpleMedia *media);
-
-/**
- * purple_media_get_account:
- * @media: The media session to retrieve the account from.
- *
- * Gets the PurpleAccount this media session is on.
- *
- * Returns: (transfer full): The account retrieved.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleAccount *purple_media_get_account(PurpleMedia *media);
-
-/**
- * purple_media_get_protocol_data:
- * @media: The media session to retrieve the protocol data from.
- *
- * Gets the protocol data from the media session.
- *
- * Returns: The protocol data retrieved.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-gpointer purple_media_get_protocol_data(PurpleMedia *media);
-
-/**
- * purple_media_set_protocol_data:
- * @media: The media session to set the protocol data on.
- * @protocol_data: The data to set on the media session.
- *
- * Sets the protocol data on the media session.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_media_set_protocol_data(PurpleMedia *media, gpointer protocol_data);
-
-/**
- * purple_media_error:
- * @media: The media object to set the state on.
- * @error: The format of the error message to send in the signal.
- * @...: The arguments to plug into the format.
- *
- * Signals an error in the media session.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_error(PurpleMedia *media, const gchar *error, ...) G_GNUC_PRINTF(2, 3);
-
-/**
- * purple_media_end:
- * @media: The media object with which to end streams.
- * @session_id: The session to end streams on.
- * @participant: The participant to end streams with.
- *
- * Ends all streams that match the given parameters
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_end(PurpleMedia *media, const gchar *session_id,
-		const gchar *participant);
-
-/**
- * purple_media_stream_info:
- * @media: The media instance to containing the stream to signal.
- * @type: The type of info being signaled.
- * @session_id: The id of the session of the stream being signaled.
- * @participant: The participant of the stream being signaled.
- * @local: TRUE if the info originated locally, FALSE if on the remote end.
- *
- * Signals different information about the given stream.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_stream_info(PurpleMedia *media, PurpleMediaInfoType type,
-		const gchar *session_id, const gchar *participant,
-		gboolean local);
-
-/**
- * purple_media_set_params:
- * @media: The media object to set the parameters on.
- * @params: (element-type utf8 GObject.Value) (transfer none): Hash table of
- *          parameters to pass.
- *
- * Sets various optional parameters of the media call.
- *
- * Currently supported are:
- *   - "sdes-cname"    : The CNAME for the RTP sessions
- *   - "sdes-name"     : Real name used to describe the source in SDES messages
- *   - "sdes-tool"     : The TOOL to put in SDES messages
- *   - "sdes-email"    : Email address to put in SDES messages
- *   - "sdes-location" : The LOCATION to put in SDES messages
- *   - "sdes-note"     : The NOTE to put in SDES messages
- *   - "sdes-phone"    : The PHONE to put in SDES messages
- *
- * Since: 2.8
- */
-PURPLE_AVAILABLE_IN_2_8
-void purple_media_set_params(PurpleMedia *media, GHashTable *params);
-
-/**
- * purple_media_get_available_params:
- * @media: The media object
- *
- * Gets the list of optional parameters supported by the media backend.
- *
- * The list is owned by the #PurpleMedia internals and should NOT be freed.
- *
- * Returns: (array zero-terminated=1) (transfer none): Names of supported
- *          parameters.
- *
- * Since: 2.8
- */
-PURPLE_AVAILABLE_IN_2_8
-const gchar **purple_media_get_available_params(PurpleMedia *media);
-
-/**
- * purple_media_param_is_supported:
- * @media: The media object
- * @param: name of parameter
- *
- * Checks if given optional parameter is supported by the media backend.
- *
- * Returns: %TRUE if backend recognizes the parameter, %FALSE otherwise.
- *
- * Since: 2.8
- */
-PURPLE_AVAILABLE_IN_2_8
-gboolean purple_media_param_is_supported(PurpleMedia *media, const gchar *param);
-
-/**
- * purple_media_add_stream:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session to add the stream to.
- * @who: The name of the remote user to add the stream for.
- * @type: The type of stream to create.
- * @initiator: Whether or not the local user initiated the stream.
- * @transmitter: The transmitter to use for the stream.
- * @params: (element-type utf8 GObject.Value) (transfer none): The stream
- *          parameters to pass to Farstream.
- *
- * Adds a stream to a session.
- *
- * It only adds a stream to one audio session or video session as
- * the @sess_id must be unique between sessions.
- *
- * Returns: %TRUE The stream was added successfully, %FALSE otherwise.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_add_stream(PurpleMedia *media, const gchar *sess_id,
-		const gchar *who, PurpleMediaSessionType type, gboolean initiator,
-		const gchar *transmitter, GHashTable *params);
-
-/**
- * purple_media_get_session_type:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session to get the type from.
- *
- * Gets the session type from a session
- *
- * Returns: The retrieved session type.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMediaSessionType purple_media_get_session_type(PurpleMedia *media, const gchar *sess_id);
-
-/**
- * purple_media_get_manager:
- * @media: The media object to get the manager instance from.
- *
- * Gets the PurpleMediaManager this media session is a part of.
- *
- * Returns: The PurpleMediaManager instance retrieved.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-struct _PurpleMediaManager *purple_media_get_manager(PurpleMedia *media);
-
-/**
- * purple_media_get_codecs:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session to get the codecs from.
- *
- * Gets the codecs from a session.
- *
- * Returns: (element-type PurpleMediaCodec) (transfer full): The retrieved
- *          codecs.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GList *purple_media_get_codecs(PurpleMedia *media, const gchar *sess_id);
-
-/**
- * purple_media_add_remote_candidates:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session find the stream in.
- * @participant: The name of the remote user to add the candidates for.
- * @remote_candidates: (element-type PurpleMediaCandidate) (transfer none): The
- *                     remote candidates to add.
- *
- * Adds remote candidates to the stream.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_add_remote_candidates(PurpleMedia *media,
-					const gchar *sess_id,
-					const gchar *participant,
-					GList *remote_candidates);
-
-/**
- * purple_media_get_local_candidates:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session to find the stream in.
- * @participant: The name of the remote user to get the candidates from.
- *
- * Gets the local candidates from a stream.
- *
- * Returns: (element-type PurpleMediaCandidate) (transfer full): The local
- *          candidates.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GList *purple_media_get_local_candidates(PurpleMedia *media,
-					 const gchar *sess_id,
-					 const gchar *participant);
-
-/**
- * purple_media_get_active_local_candidates:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session to find the stream in.
- * @participant: The name of the remote user to get the active candidate
- *                    from.
- *
- * Gets the active local candidates for the stream.
- *
- * Returns: (element-type PurpleMediaCandidate) (transfer full): The active
- *          candidates retrieved.
- *
- * Since: 2.8
- */
-PURPLE_AVAILABLE_IN_2_8
-GList *purple_media_get_active_local_candidates(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant);
-
-/**
- * purple_media_get_active_remote_candidates:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session to find the stream in.
- * @participant: The name of the remote user to get the remote candidate
- *                    from.
- *
- * Gets the active remote candidates for the stream.
- *
- * Returns: (element-type PurpleMediaCandidate) (transfer full): The remote
- *          candidates retrieved.
- *
- * Since: 2.8
- */
-PURPLE_AVAILABLE_IN_2_8
-GList *purple_media_get_active_remote_candidates(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant);
-
-/**
- * purple_media_set_remote_codecs:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session find the stream in.
- * @participant: The name of the remote user to set the codecs for.
- * @codecs: (element-type PurpleMediaCodec) (transfer none): The list of remote
- *          codecs to set.
- *
- * Sets remote codecs from the stream.
- *
- * Returns: %TRUE The codecs were set successfully, or %FALSE otherwise.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id,
-					const gchar *participant, GList *codecs);
-
-/**
- * purple_media_candidates_prepared:
- * @media: The media object to find the remote user in.
- * @session_id: The session id of the session to check.
- * @participant: The remote user to check for.
- *
- * Returns whether or not the candidates for set of streams are prepared
- *
- * Returns: %TRUE All streams for the given session_id/participant combination have candidates prepared, %FALSE otherwise.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_candidates_prepared(PurpleMedia *media,
-		const gchar *session_id, const gchar *participant);
-
-/**
- * purple_media_set_send_codec:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session to set the codec for.
- * @codec: The codec to set the session to stream.
- *
- * Sets the send codec for the a session.
- *
- * Returns: %TRUE The codec was successfully changed, or %FALSE otherwise.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMediaCodec *codec);
-
-/**
- * purple_media_set_encryption_parameters:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session to set parameters of.
- * @cipher: The cipher to use to encrypt our media in the session.
- * @auth: The algorithm to use to compute authentication codes for our media
- *        frames.
- * @key: The encryption key.
- * @key_len: Byte length of the encryption key.
- *
- * Sets the encryption parameters of our media in the session.
- *
- * Returns: %TRUE if the encryption parameters were set successfully.
- *
- * Since: 2.11
- */
-PURPLE_AVAILABLE_IN_2_11
-gboolean purple_media_set_encryption_parameters(PurpleMedia *media,
-		const gchar *sess_id, const gchar *cipher,
-		const gchar *auth, const gchar *key, gsize key_len);
-
-/**
- * purple_media_set_decryption_parameters:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session to set parameters of.
- * @participant: The participant of the session to set parameters of.
- * @cipher: The cipher to use to decrypt media coming from this session's
- *          participant.
- * @auth: The algorithm to use for authentication of the media coming from
- *        the session's participant.
- * @key: The decryption key.
- * @key_len: Byte length of the decryption key.
- *
- * Sets the decryption parameters for a session participant's media.
- *
- * Returns: %TRUE if the decryption parameters were set successfully.
- *
- * Since: 2.11
- */
-PURPLE_AVAILABLE_IN_2_11
-gboolean purple_media_set_decryption_parameters(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant,
-		const gchar *cipher, const gchar *auth,
-		const gchar *key, gsize key_len);
-
-/**
- * purple_media_set_require_encryption:
- * @media: The media object to find the session in.
- * @sess_id: The id of the session to set parameters of.
- * @participant: The participant of the session to set parameters of.
- * @require_encryption: TRUE if the media requires encryption.
- *
- * Sets whether a session participant's media requires encryption.
- *
- * Returns: %TRUE if the encryption requirement was set successfully.
- *
- * Since: 2.14
- */
-PURPLE_AVAILABLE_IN_2_14
-gboolean purple_media_set_require_encryption(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant,
-		gboolean require_encryption);
-
-/**
- * purple_media_codecs_ready:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session to check.
- *
- * Gets whether a session's codecs are ready to be used.
- *
- * Returns: %TRUE The codecs are ready, or %FALSE otherwise.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id);
-
-/**
- * purple_media_set_send_rtcp_mux:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session find the stream in.
- * @participant: The name of the remote user to set the rtcp-mux for.
- * @send_rtcp_mux: Whether to enable the rtcp-mux option
- *
- * Sets the rtcp-mux option for the stream.
- *
- * Returns: %TRUE RTCP-Mux was set successfully, or %FALSE otherwise.
- *
- * Since: 2.11
- */
-PURPLE_AVAILABLE_IN_2_11
-gboolean purple_media_set_send_rtcp_mux(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant, gboolean send_rtcp_mux);
-/**
- * purple_media_is_initiator:
- * @media: The media instance to find the session in.
- * @sess_id: The session id of the session to check.
- * @participant: The participant of the stream to check.
- *
- * Gets whether the local user is the conference/session/stream's initiator.
- *
- * Returns: TRUE if the local user is the stream's initiator, else FALSE.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_is_initiator(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant);
-
-/**
- * purple_media_accepted:
- * @media: The media object to find the session in.
- * @sess_id: The session id of the session to check.
- * @participant: The participant to check.
- *
- * Gets whether a streams selected have been accepted.
- *
- * Returns: %TRUE The selected streams have been accepted, or %FALSE otherwise.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_accepted(PurpleMedia *media, const gchar *sess_id,
-		const gchar *participant);
-
-/**
- * purple_media_set_input_volume:
- * @media: The media object the sessions are in.
- * @session_id: The session to select (if any).
- * @level: The level to set the volume to.
- *
- * Sets the input volume of all the selected sessions.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_set_input_volume(PurpleMedia *media, const gchar *session_id, double level);
-
-/**
- * purple_media_set_output_volume:
- * @media: The media object the streams are in.
- * @session_id: The session to limit the streams to (if any).
- * @participant: The participant to limit the streams to (if any).
- * @level: The level to set the volume to.
- *
- * Sets the output volume of all the selected streams.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_set_output_volume(PurpleMedia *media, const gchar *session_id,
-		const gchar *participant, double level);
-
-/**
- * purple_media_set_output_window:
- * @media: The media instance to set the output window on.
- * @session_id: The session to set the output window on.
- * @participant: Optionally, the participant to set the output window on.
- *
- * Sets a video output window for the given session/stream.
- *
- * Returns: An id to reference the output window.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gulong purple_media_set_output_window(PurpleMedia *media,
-		const gchar *session_id, const gchar *participant);
-
-/**
- * purple_media_remove_output_windows:
- * @media: The instance to remove all output windows from.
- *
- * Removes all output windows from a given media session.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_remove_output_windows(PurpleMedia *media);
-
-/**
- * purple_media_send_dtmf:
- * @media: The media instance to send a DTMF signal to.
- * @session_id: The session id of the session to send the DTMF signal on.
- * @dtmf: The character representing the DTMF in the range [0-9#*A-D].
- * @volume: The power level expressed in dBm0 after dropping the sign in the
- *          range of 0 to 63.  A larger value represents a lower volume.
- * @duration: The duration of the tone in milliseconds.
- *
- * Sends a DTMF signal out-of-band.
- *
- * Returns: %TRUE DTMF sent successfully, or %FALSE otherwise.
- *
- * Since: 2.11
- */
-PURPLE_AVAILABLE_IN_2_11
-gboolean purple_media_send_dtmf(PurpleMedia *media, const gchar *session_id,
-		gchar dtmf, guint8 volume, guint16 duration);
-
-G_END_DECLS
-
-#endif /* PURPLE_MEDIA_H */
diff --git a/libpurple/media.c b/libpurple/media.c
deleted file mode 100644
--- a/libpurple/media.c
+++ /dev/null
@@ -1,1408 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "media.h"
-#include "media/backend-iface.h"
-#include "mediamanager.h"
-#include "purpleaccount.h"
-
-#include "debug.h"
-
-#include "media-gst.h"
-
-typedef struct _PurpleMediaSession PurpleMediaSession;
-typedef struct _PurpleMediaStream PurpleMediaStream;
-
-struct _PurpleMediaSession
-{
-	gchar *id;
-	PurpleMedia *media;
-	PurpleMediaSessionType type;
-	gboolean initiator;
-};
-
-struct _PurpleMediaStream
-{
-	PurpleMediaSession *session;
-	gchar *participant;
-
-	GList *local_candidates;
-	GList *remote_candidates;
-
-	gboolean initiator;
-	gboolean accepted;
-	gboolean candidates_prepared;
-
-	GList *active_local_candidates;
-	GList *active_remote_candidates;
-};
-
-struct _PurpleMediaPrivate
-{
-	PurpleMediaManager *manager;
-	PurpleAccount *account;
-	PurpleMediaBackend *backend;
-	gchar *conference_type;
-	gboolean initiator;
-	gpointer protocol_data;
-
-	GHashTable *sessions;	/* PurpleMediaSession table */
-	GList *participants;
-	GList *streams;		/* PurpleMediaStream table */
-};
-
-static void purple_media_class_init (PurpleMediaClass *klass);
-static void purple_media_init (PurpleMedia *media);
-static void purple_media_dispose (GObject *object);
-static void purple_media_finalize (GObject *object);
-static void purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-static void purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-
-static void purple_media_new_local_candidate_cb(PurpleMediaBackend *backend,
-		const gchar *sess_id, const gchar *participant,
-		PurpleMediaCandidate *candidate, PurpleMedia *media);
-static void purple_media_candidates_prepared_cb(PurpleMediaBackend *backend,
-		const gchar *sess_id, const gchar *name, PurpleMedia *media);
-static void purple_media_candidate_pair_established_cb(
-		PurpleMediaBackend *backend,
-		const gchar *sess_id, const gchar *name,
-		PurpleMediaCandidate *local_candidate,
-		PurpleMediaCandidate *remote_candidate,
-		PurpleMedia *media);
-static void purple_media_codecs_changed_cb(PurpleMediaBackend *backend,
-		const gchar *sess_id, PurpleMedia *media);
-
-
-enum {
-	SIG_ERROR,
-	SIG_CANDIDATES_PREPARED,
-	SIG_CODECS_CHANGED,
-	SIG_LEVEL,
-	SIG_NEW_CANDIDATE,
-	SIG_STATE_CHANGED,
-	SIG_STREAM_INFO,
-	SIG_CANDIDATE_PAIR_ESTABLISHED,
-	N_SIGNALS,
-};
-static guint signals[N_SIGNALS] = {0, };
-
-enum {
-	PROP_0,
-	PROP_MANAGER,
-	PROP_BACKEND,
-	PROP_ACCOUNT,
-	PROP_CONFERENCE_TYPE,
-	PROP_INITIATOR,
-	PROP_PROTOCOL_DATA,
-	N_PROPERTIES,
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE(PurpleMedia, purple_media, G_TYPE_OBJECT);
-
-static void
-purple_media_class_init (PurpleMediaClass *klass)
-{
-	GObjectClass *gobject_class = (GObjectClass*)klass;
-
-	gobject_class->dispose = purple_media_dispose;
-	gobject_class->finalize = purple_media_finalize;
-	gobject_class->set_property = purple_media_set_property;
-	gobject_class->get_property = purple_media_get_property;
-
-	/**
-	 * PurpleMedia:manager:
-	 *
-	 * The manager that this media is tied to.
-	 */
-	g_object_class_install_property(gobject_class, PROP_MANAGER,
-			g_param_spec_object("manager",
-			"Purple Media Manager",
-			"The media manager that contains this media session.",
-			PURPLE_TYPE_MEDIA_MANAGER,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMedia:backend:
-	 *
-	 * The backend for this media.
-	 */
-	/*
-	 * This one should be PURPLE_TYPE_MEDIA_BACKEND, but it doesn't
-	 * like interfaces because they "aren't GObjects"
-	 */
-	g_object_class_install_property(gobject_class, PROP_BACKEND,
-			g_param_spec_object("backend",
-			"Purple Media Backend",
-			"The backend object this media object uses.",
-			G_TYPE_OBJECT,
-			G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMedia:account:
-	 *
-	 * The [class@Account] that this media belongs to.
-	 */
-	g_object_class_install_property(gobject_class, PROP_ACCOUNT,
-			g_param_spec_object("account", "PurpleAccount",
-			"The account this media session is on.",
-			PURPLE_TYPE_ACCOUNT,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMedia:conference-type:
-	 *
-	 * The conference type of this media.
-	 */
-	g_object_class_install_property(gobject_class, PROP_CONFERENCE_TYPE,
-			g_param_spec_string("conference-type",
-			"Conference Type",
-			"The type of conference that this media object "
-			"has been created to provide.",
-			NULL,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMedia:initiator:
-	 *
-	 * Whether or not the local user initiated the conference.
-	 */
-	g_object_class_install_property(gobject_class, PROP_INITIATOR,
-			g_param_spec_boolean("initiator",
-			"initiator",
-			"If the local user initiated the conference.",
-			FALSE,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMedia:protocol-data:
-	 *
-	 * Protocol specific data for the media.
-	 */
-	g_object_class_install_property(gobject_class, PROP_PROTOCOL_DATA,
-			g_param_spec_pointer("protocol-data",
-			"gpointer",
-			"Data the protocol set on the media session.",
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMedia::error:
-	 * @media: The instance.
-	 * @message: The error message.
-	 *
-	 * Emitted by [method@Media.error].
-	 */
-	signals[SIG_ERROR] = g_signal_new("error", G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-					 G_TYPE_NONE, 1, G_TYPE_STRING);
-
-	/**
-	 * PurpleMedia::candidates-prepared:
-	 * @media: The instance.
-	 * @session_id: The session id.
-	 * @name: The candidate element name.
-	 *
-	 * Emitted when a candidate element has been determined.
-	 */
-	signals[SIG_CANDIDATES_PREPARED] = g_signal_new("candidates-prepared",
-					 G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-					 G_TYPE_NONE, 2, G_TYPE_STRING,
-					 G_TYPE_STRING);
-
-	/**
-	 * PurpleMedia::codecs-changed:
-	 * @media: The instance.
-	 * @session_id: The session id.
-	 *
-	 * Emitted when the codecs have changed.
-	 */
-	signals[SIG_CODECS_CHANGED] = g_signal_new("codecs-changed",
-					 G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-					 G_TYPE_NONE, 1, G_TYPE_STRING);
-
-	/**
-	 * PurpleMedia::level:
-	 * @media: The instance.
-	 * @session_id: The session.
-	 * @participant: The participant.
-	 * @level: The new level.
-	 *
-	 * Emitted when the volume of a participant has changed. I think?
-	 */
-	signals[SIG_LEVEL] = g_signal_new("level",
-					 G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-					 G_TYPE_NONE, 3, G_TYPE_STRING,
-					 G_TYPE_STRING, G_TYPE_DOUBLE);
-
-
-	/**
-	 * PurpleMedia::new-candidate:
-	 * @media: The instance.
-	 * @session_id: The session id.
-	 * @participant: The participant.
-	 * @candidate: The new candidate.
-	 *
-	 * Emitted when a new media candidate is available.
-	 */
-	signals[SIG_NEW_CANDIDATE] = g_signal_new("new-candidate",
-					 G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-					 G_TYPE_NONE, 3, G_TYPE_POINTER,
-					 G_TYPE_POINTER, PURPLE_MEDIA_TYPE_CANDIDATE);
-
-	/**
-	 * PurpleMedia::state-changed:
-	 * @media: The instance.
-	 * @newstate: The new state.
-	 * @session_id: The session id.
-	 * @participant: The participant.
-	 *
-	 * Emitted when the media's state has changed.
-	 */
-	signals[SIG_STATE_CHANGED] = g_signal_new("state-changed",
-					 G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-					 G_TYPE_NONE, 3, PURPLE_MEDIA_TYPE_STATE,
-					 G_TYPE_STRING, G_TYPE_STRING);
-
-	/**
-	 * PurpleMedia::stream-info:
-	 * @media: The instance.
-	 * @type: The type of the media.
-	 * @session_id: The session id.
-	 * @participant: The participant.
-	 * @local: Whether this request originated from the libpurple user.
-	 *
-	 * Emitted when information about the stream is available.
-	 */
-	signals[SIG_STREAM_INFO] = g_signal_new("stream-info",
-					 G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-					 G_TYPE_NONE, 4, PURPLE_MEDIA_TYPE_INFO_TYPE,
-					 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
-
-	/**
-	 * PurpleMedia::candidate-pair-established:
-	 * @media: The instance.
-	 * @session_id: The session id.
-	 * @name: The element name.
-	 * @local_candidate: The local candidate.
-	 * @remote_candidate: The remote candidate.
-	 *
-	 * Emitted when candidates have been established for a session.
-	 */
-	signals[SIG_CANDIDATE_PAIR_ESTABLISHED] = g_signal_new("candidate-pair-established",
-					 G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-					 G_TYPE_NONE, 4, G_TYPE_POINTER, G_TYPE_POINTER,
-					 PURPLE_MEDIA_TYPE_CANDIDATE, PURPLE_MEDIA_TYPE_CANDIDATE);
-}
-
-
-static void
-purple_media_init (PurpleMedia *media)
-{
-	media->priv = purple_media_get_instance_private(media);
-	memset(media->priv, 0, sizeof(*media->priv));
-}
-
-static void
-purple_media_stream_free(PurpleMediaStream *stream)
-{
-	if (stream == NULL) {
-		return;
-	}
-
-	g_free(stream->participant);
-
-	g_clear_pointer(&stream->local_candidates,
-	                purple_media_candidate_list_free);
-	g_clear_pointer(&stream->remote_candidates,
-	                purple_media_candidate_list_free);
-	g_clear_pointer(&stream->active_local_candidates,
-	                purple_media_candidate_list_free);
-	g_clear_pointer(&stream->active_remote_candidates,
-	                purple_media_candidate_list_free);
-
-	g_free(stream);
-}
-
-static void
-purple_media_session_free(PurpleMediaSession *session)
-{
-	if (session == NULL) {
-		return;
-	}
-
-	g_free(session->id);
-	g_free(session);
-}
-
-static void
-purple_media_dispose(GObject *media)
-{
-	PurpleMediaPrivate *priv =
-			purple_media_get_instance_private(PURPLE_MEDIA(media));
-
-	purple_debug_info("media","purple_media_dispose\n");
-
-	purple_media_manager_remove_media(priv->manager, PURPLE_MEDIA(media));
-
-	g_clear_object(&priv->backend);
-	g_clear_object(&priv->manager);
-	g_clear_pointer(&priv->conference_type, g_free);
-
-	G_OBJECT_CLASS(purple_media_parent_class)->dispose(media);
-}
-
-static void
-purple_media_finalize(GObject *media)
-{
-	PurpleMediaPrivate *priv =
-			purple_media_get_instance_private(PURPLE_MEDIA(media));
-	purple_debug_info("media","purple_media_finalize\n");
-
-	g_list_free_full(priv->streams, (GDestroyNotify)purple_media_stream_free);
-	g_list_free_full(priv->participants, g_free);
-
-	if (priv->sessions) {
-		GList *sessions = g_hash_table_get_values(priv->sessions);
-		g_list_free_full(sessions, (GDestroyNotify)purple_media_session_free);
-		g_hash_table_destroy(priv->sessions);
-	}
-
-	G_OBJECT_CLASS(purple_media_parent_class)->finalize(media);
-}
-
-static void
-purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
-	PurpleMedia *media;
-	g_return_if_fail(PURPLE_IS_MEDIA(object));
-
-	media = PURPLE_MEDIA(object);
-
-	switch (prop_id) {
-		case PROP_MANAGER:
-			media->priv->manager = g_value_dup_object(value);
-			break;
-		case PROP_ACCOUNT:
-			media->priv->account = g_value_get_object(value);
-			break;
-		case PROP_CONFERENCE_TYPE:
-			media->priv->conference_type = g_value_dup_string(value);
-			media->priv->backend = g_object_new(
-					purple_media_manager_get_backend_type(purple_media_manager_get()),
-					"conference-type", media->priv->conference_type,
-					"media", media,
-					NULL);
-			g_signal_connect(media->priv->backend,
-					"active-candidate-pair",
-					G_CALLBACK(purple_media_candidate_pair_established_cb),
-					media);
-			g_signal_connect(media->priv->backend,
-					"candidates-prepared",
-					G_CALLBACK(purple_media_candidates_prepared_cb),
-					media);
-			g_signal_connect(media->priv->backend,
-					"codecs-changed",
-					G_CALLBACK(purple_media_codecs_changed_cb),
-					media);
-			g_signal_connect(media->priv->backend,
-					"new-candidate",
-					G_CALLBACK(purple_media_new_local_candidate_cb),
-					media);
-			break;
-		case PROP_INITIATOR:
-			media->priv->initiator = g_value_get_boolean(value);
-			break;
-		case PROP_PROTOCOL_DATA:
-			media->priv->protocol_data = g_value_get_pointer(value);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
-	PurpleMedia *media;
-	g_return_if_fail(PURPLE_IS_MEDIA(object));
-
-	media = PURPLE_MEDIA(object);
-
-	switch (prop_id) {
-		case PROP_MANAGER:
-			g_value_set_object(value, media->priv->manager);
-			break;
-		case PROP_BACKEND:
-			g_value_set_object(value, media->priv->backend);
-			break;
-		case PROP_ACCOUNT:
-			g_value_set_object(value, media->priv->account);
-			break;
-		case PROP_CONFERENCE_TYPE:
-			g_value_set_string(value, media->priv->conference_type);
-			break;
-		case PROP_INITIATOR:
-			g_value_set_boolean(value, media->priv->initiator);
-			break;
-		case PROP_PROTOCOL_DATA:
-			g_value_set_pointer(value, media->priv->protocol_data);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-			break;
-	}
-
-}
-
-static PurpleMediaSession*
-purple_media_get_session(PurpleMedia *media, const gchar *sess_id)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	return (PurpleMediaSession*) (media->priv->sessions) ?
-			g_hash_table_lookup(media->priv->sessions, sess_id) : NULL;
-}
-
-static PurpleMediaStream*
-purple_media_get_stream(PurpleMedia *media, const gchar *session, const gchar *participant)
-{
-	GList *streams;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-
-	streams = media->priv->streams;
-
-	for (; streams; streams = g_list_next(streams)) {
-		PurpleMediaStream *stream = streams->data;
-		if (purple_strequal(stream->session->id, session) &&
-				purple_strequal(stream->participant, participant))
-		{
-			return stream;
-		}
-	}
-
-	return NULL;
-}
-
-static GList *
-purple_media_get_streams(PurpleMedia *media, const gchar *session,
-		const gchar *participant)
-{
-	GList *streams;
-	GList *ret = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-
-	streams = media->priv->streams;
-
-	for (; streams; streams = g_list_next(streams)) {
-		PurpleMediaStream *stream = streams->data;
-		if ((session == NULL ||
-				purple_strequal(stream->session->id, session)) &&
-				(participant == NULL ||
-				purple_strequal(stream->participant, participant)))
-		{
-			ret = g_list_append(ret, stream);
-		}
-	}
-
-	return ret;
-}
-
-static void
-purple_media_add_session(PurpleMedia *media, PurpleMediaSession *session)
-{
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-	g_return_if_fail(session != NULL);
-
-	if (!media->priv->sessions) {
-		purple_debug_info("media", "Creating hash table for sessions\n");
-		media->priv->sessions = g_hash_table_new_full(g_str_hash, g_str_equal,
-		                                              g_free, NULL);
-	}
-	g_hash_table_insert(media->priv->sessions, g_strdup(session->id), session);
-}
-
-static PurpleMediaStream *
-purple_media_insert_stream(PurpleMediaSession *session,
-		const gchar *name, gboolean initiator)
-{
-	PurpleMediaStream *media_stream;
-
-	g_return_val_if_fail(session != NULL, NULL);
-
-	media_stream = g_new0(PurpleMediaStream, 1);
-	media_stream->participant = g_strdup(name);
-	media_stream->session = session;
-	media_stream->initiator = initiator;
-
-	session->media->priv->streams =
-			g_list_append(session->media->priv->streams, media_stream);
-
-	return media_stream;
-}
-
-static void
-purple_media_insert_local_candidate(PurpleMediaSession *session, const gchar *name,
-				     PurpleMediaCandidate *candidate)
-{
-	PurpleMediaStream *stream;
-
-	g_return_if_fail(session != NULL);
-
-	stream = purple_media_get_stream(session->media, session->id, name);
-	stream->local_candidates = g_list_append(stream->local_candidates, candidate);
-}
-
-GList *
-purple_media_get_session_ids(PurpleMedia *media)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	return media->priv->sessions != NULL ?
-			g_hash_table_get_keys(media->priv->sessions) : NULL;
-}
-
-GstElement *
-purple_media_get_src(PurpleMedia *media, G_GNUC_UNUSED const char *sess_id)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-
-	return NULL;
-}
-
-PurpleAccount *
-purple_media_get_account(PurpleMedia *media)
-{
-	PurpleAccount *account;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	g_object_get(media, "account", &account, NULL);
-	return account;
-}
-
-gpointer
-purple_media_get_protocol_data(PurpleMedia *media)
-{
-	gpointer protocol_data;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	g_object_get(media, "protocol-data", &protocol_data, NULL);
-	return protocol_data;
-}
-
-void
-purple_media_set_protocol_data(PurpleMedia *media, gpointer protocol_data)
-{
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-	g_object_set(media, "protocol-data", protocol_data, NULL);
-}
-
-void
-purple_media_error(PurpleMedia *media, const gchar *error, ...)
-{
-	va_list args;
-	gchar *message;
-
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-	va_start(args, error);
-	message = g_strdup_vprintf(error, args);
-	va_end(args);
-
-	purple_debug_error("media", "%s\n", message);
-	g_signal_emit(media, signals[SIG_ERROR], 0, message);
-
-	g_free(message);
-}
-
-void
-purple_media_end(PurpleMedia *media,
-		const gchar *session_id, const gchar *participant)
-{
-	GList *iter, *sessions = NULL, *participants = NULL;
-
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-	iter = purple_media_get_streams(media, session_id, participant);
-
-	/* Free matching streams */
-	for (; iter; iter = g_list_delete_link(iter, iter)) {
-		PurpleMediaStream *stream = iter->data;
-
-		g_signal_emit(media, signals[SIG_STATE_CHANGED],
-				0, PURPLE_MEDIA_STATE_END,
-				stream->session->id, stream->participant);
-
-		media->priv->streams =
-				g_list_remove(media->priv->streams, stream);
-
-		if (g_list_find(sessions, stream->session) == NULL) {
-			sessions = g_list_prepend(sessions, stream->session);
-		}
-
-		if (g_list_find_custom(participants, stream->participant,
-				(GCompareFunc)strcmp) == NULL)
-		{
-			participants = g_list_prepend(participants,
-					g_strdup(stream->participant));
-		}
-
-		purple_media_stream_free(stream);
-	}
-
-	iter = media->priv->streams;
-
-	/* Reduce to list of sessions to remove */
-	for (; iter; iter = g_list_next(iter)) {
-		PurpleMediaStream *stream = iter->data;
-
-		sessions = g_list_remove(sessions, stream->session);
-	}
-
-	/* Free sessions with no streams left */
-	for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
-		PurpleMediaSession *session = sessions->data;
-
-		g_signal_emit(media, signals[SIG_STATE_CHANGED],
-				0, PURPLE_MEDIA_STATE_END,
-				session->id, NULL);
-
-		g_hash_table_remove(media->priv->sessions, session->id);
-		purple_media_session_free(session);
-	}
-
-	iter = media->priv->streams;
-
-	/* Reduce to list of participants to remove */
-	for (; iter; iter = g_list_next(iter)) {
-		PurpleMediaStream *stream = iter->data;
-		GList *tmp;
-
-		tmp = g_list_find_custom(participants,
-				stream->participant, (GCompareFunc)strcmp);
-
-		if (tmp != NULL) {
-			g_free(tmp->data);
-			participants = g_list_delete_link(participants,	tmp);
-		}
-	}
-
-	/* Remove participants with no streams left (just emit the signal) */
-	for (; participants; participants =
-			g_list_delete_link(participants, participants)) {
-		gchar *participant = participants->data;
-		GList *link = g_list_find_custom(media->priv->participants,
-				participant, (GCompareFunc)strcmp);
-
-		g_signal_emit(media, signals[SIG_STATE_CHANGED],
-				0, PURPLE_MEDIA_STATE_END,
-				NULL, participant);
-
-		if (link != NULL) {
-			g_free(link->data);
-			media->priv->participants = g_list_delete_link(
-					media->priv->participants, link);
-		}
-
-		g_free(participant);
-	}
-
-	/* Free the conference if no sessions left */
-	if (media->priv->sessions != NULL &&
-			g_hash_table_size(media->priv->sessions) == 0) {
-		g_signal_emit(media, signals[SIG_STATE_CHANGED],
-				0, PURPLE_MEDIA_STATE_END,
-				NULL, NULL);
-		g_object_unref(media);
-		return;
-	}
-}
-
-void
-purple_media_stream_info(PurpleMedia *media, PurpleMediaInfoType type,
-		const gchar *session_id, const gchar *participant,
-		gboolean local)
-{
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-	if (type == PURPLE_MEDIA_INFO_ACCEPT) {
-		GList *streams, *sessions = NULL, *participants = NULL;
-
-		g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-		streams = purple_media_get_streams(media, session_id, participant);
-
-		/* Emit stream acceptance */
-		for (; streams; streams = g_list_delete_link(streams, streams)) {
-			PurpleMediaStream *stream = streams->data;
-
-			stream->accepted = TRUE;
-
-			g_signal_emit(media, signals[SIG_STREAM_INFO],
-					0, type, stream->session->id,
-					stream->participant, local);
-
-			if (g_list_find(sessions, stream->session) == NULL) {
-				sessions = g_list_prepend(sessions, stream->session);
-			}
-
-			if (g_list_find_custom(participants,
-					stream->participant,
-					(GCompareFunc)strcmp) == NULL) {
-				participants = g_list_prepend(participants,
-						g_strdup(stream->participant));
-			}
-		}
-
-		/* Emit session acceptance */
-		for (; sessions; sessions =
-				g_list_delete_link(sessions, sessions)) {
-			PurpleMediaSession *session = sessions->data;
-
-			if (purple_media_accepted(media, session->id, NULL)) {
-				g_signal_emit(media, signals[SIG_STREAM_INFO],
-						0, PURPLE_MEDIA_INFO_ACCEPT,
-						session->id, NULL, local);
-			}
-		}
-
-		/* Emit participant acceptance */
-		for (; participants; participants = g_list_delete_link(
-				participants, participants)) {
-			gchar *participant = participants->data;
-
-			if (purple_media_accepted(media, NULL, participant)) {
-				g_signal_emit(media, signals[SIG_STREAM_INFO],
-						0, PURPLE_MEDIA_INFO_ACCEPT,
-						NULL, participant, local);
-			}
-
-			g_free(participant);
-		}
-
-		/* Emit conference acceptance */
-		if (purple_media_accepted(media, NULL, NULL)) {
-			g_signal_emit(media, signals[SIG_STREAM_INFO],
-					0, PURPLE_MEDIA_INFO_ACCEPT,
-					NULL, NULL, local);
-		}
-
-		return;
-	} else if (type == PURPLE_MEDIA_INFO_HANGUP ||
-			type == PURPLE_MEDIA_INFO_REJECT) {
-		GList *streams;
-
-		g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-		streams = purple_media_get_streams(media, session_id, participant);
-
-		/* Emit for stream */
-		for (; streams; streams = g_list_delete_link(streams, streams)) {
-			PurpleMediaStream *stream = streams->data;
-
-			g_signal_emit(media, signals[SIG_STREAM_INFO],
-					0, type, stream->session->id,
-					stream->participant, local);
-		}
-
-		if (session_id != NULL && participant != NULL) {
-			/* Everything that needs to be emitted has been */
-		} else if (session_id == NULL && participant == NULL) {
-			/* Emit for everything in the conference */
-			GList *sessions = NULL;
-			GList *participants = media->priv->participants;
-
-			if (media->priv->sessions != NULL) {
-				sessions = g_hash_table_get_values(
-					media->priv->sessions);
-			}
-
-			/* Emit for sessions */
-			for (; sessions; sessions = g_list_delete_link(
-					sessions, sessions)) {
-				PurpleMediaSession *session = sessions->data;
-
-				g_signal_emit(media, signals[SIG_STREAM_INFO],
-						0, type,
-						session->id, NULL, local);
-			}
-
-			/* Emit for participants */
-			for (; participants; participants =
-					g_list_next(participants)) {
-				gchar *participant = participants->data;
-
-				g_signal_emit(media, signals[SIG_STREAM_INFO],
-						0, type,
-						NULL, participant, local);
-			}
-
-			/* Emit for conference */
-			g_signal_emit(media, signals[SIG_STREAM_INFO],
-					0, type, NULL, NULL, local);
-		} else if (session_id != NULL) {
-			/* Emit just the specific session */
-			PurpleMediaSession *session =
-					purple_media_get_session(
-					media, session_id);
-
-			if (session == NULL) {
-				purple_debug_warning("media",
-						"Couldn't find session"
-						" to hangup/reject.\n");
-			} else {
-				g_signal_emit(media, signals[SIG_STREAM_INFO],
-						0, type,
-						session->id, NULL, local);
-			}
-		} else if (participant != NULL) {
-			/* Emit just the specific participant */
-			if (!g_list_find_custom(media->priv->participants,
-					participant, (GCompareFunc)strcmp)) {
-				purple_debug_warning("media",
-						"Couldn't find participant"
-						" to hangup/reject.\n");
-			} else {
-				g_signal_emit(media, signals[SIG_STREAM_INFO],
-						0, type, NULL,
-						participant, local);
-			}
-		}
-
-		purple_media_end(media, session_id, participant);
-		return;
-	}
-
-	g_signal_emit(media, signals[SIG_STREAM_INFO],
-			0, type, session_id, participant, local);
-}
-
-void
-purple_media_set_params(PurpleMedia *media, GHashTable *params)
-{
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-	purple_media_backend_set_params(media->priv->backend, params);
-}
-
-const gchar **
-purple_media_get_available_params(PurpleMedia *media)
-{
-	static const gchar *NULL_ARRAY[] = { NULL };
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL_ARRAY);
-
-	return purple_media_backend_get_available_params(media->priv->backend);
-}
-
-gboolean
-purple_media_param_is_supported(PurpleMedia *media, const gchar *param)
-{
-	const gchar **params;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-	g_return_val_if_fail(param != NULL, FALSE);
-
-	params = purple_media_backend_get_available_params(media->priv->backend);
-	for (; *params != NULL; ++params) {
-		if (purple_strequal(*params, param)) {
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
-
-static void
-purple_media_new_local_candidate_cb(G_GNUC_UNUSED PurpleMediaBackend *backend,
-		const gchar *sess_id, const gchar *participant,
-		PurpleMediaCandidate *candidate, PurpleMedia *media)
-{
-	PurpleMediaSession *session =
-			purple_media_get_session(media, sess_id);
-
-	purple_media_insert_local_candidate(session, participant,
-			purple_media_candidate_copy(candidate));
-
-	g_signal_emit(session->media, signals[SIG_NEW_CANDIDATE],
-		      0, session->id, participant, candidate);
-}
-
-static void
-purple_media_candidates_prepared_cb(G_GNUC_UNUSED PurpleMediaBackend *backend,
-		const gchar *sess_id, const gchar *name, PurpleMedia *media)
-{
-	PurpleMediaStream *stream_data;
-
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-	stream_data = purple_media_get_stream(media, sess_id, name);
-	stream_data->candidates_prepared = TRUE;
-
-	g_signal_emit(media, signals[SIG_CANDIDATES_PREPARED],
-			0, sess_id, name);
-}
-
-/* callback called when a pair of transport candidates (local and remote)
- * has been established */
-static void
-purple_media_candidate_pair_established_cb(G_GNUC_UNUSED PurpleMediaBackend *backend,
-		const gchar *sess_id, const gchar *name,
-		PurpleMediaCandidate *local_candidate,
-		PurpleMediaCandidate *remote_candidate,
-		PurpleMedia *media)
-{
-	PurpleMediaStream *stream;
-	GList *iter;
-	guint id;
-
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-	stream = purple_media_get_stream(media, sess_id, name);
-	id = purple_media_candidate_get_component_id(local_candidate);
-
-	iter = stream->active_local_candidates;
-	for(; iter; iter = g_list_next(iter)) {
-		PurpleMediaCandidate *c = iter->data;
-		if (id == purple_media_candidate_get_component_id(c)) {
-			g_object_unref(c);
-			stream->active_local_candidates = g_list_delete_link(
-					stream->active_local_candidates,
-					iter);
-			break;
-		}
-	}
-	stream->active_local_candidates = g_list_prepend(
-			stream->active_local_candidates,
-			purple_media_candidate_copy(
-			local_candidate));
-
-	id = purple_media_candidate_get_component_id(local_candidate);
-
-	iter = stream->active_remote_candidates;
-	for(; iter; iter = g_list_next(iter)) {
-		PurpleMediaCandidate *c = iter->data;
-		if (id == purple_media_candidate_get_component_id(c)) {
-			g_object_unref(c);
-			stream->active_remote_candidates = g_list_delete_link(
-					stream->active_remote_candidates,
-					iter);
-			break;
-		}
-	}
-	stream->active_remote_candidates = g_list_prepend(
-			stream->active_remote_candidates,
-			purple_media_candidate_copy(
-			remote_candidate));
-
-	g_signal_emit(media, signals[SIG_CANDIDATE_PAIR_ESTABLISHED],
-		0, sess_id, name, local_candidate, remote_candidate);
-	purple_debug_info("media", "candidate pair established\n");
-}
-
-static void
-purple_media_codecs_changed_cb(G_GNUC_UNUSED PurpleMediaBackend *backend,
-		const gchar *sess_id, PurpleMedia *media)
-{
-	g_signal_emit(media, signals[SIG_CODECS_CHANGED], 0, sess_id);
-}
-
-gboolean
-purple_media_add_stream(PurpleMedia *media, const gchar *sess_id,
-		const gchar *who, PurpleMediaSessionType type, gboolean initiator,
-		const gchar *transmitter, GHashTable *params)
-{
-	PurpleMediaSession *session;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	if (!purple_media_backend_add_stream(media->priv->backend,
-			sess_id, who, type, initiator, transmitter, params))
-	{
-		purple_debug_error("media", "Error adding stream.\n");
-		return FALSE;
-	}
-
-	session = purple_media_get_session(media, sess_id);
-
-	if (!session) {
-		session = g_new0(PurpleMediaSession, 1);
-		session->id = g_strdup(sess_id);
-		session->media = media;
-		session->type = type;
-		session->initiator = initiator;
-
-		purple_media_add_session(media, session);
-		g_signal_emit(media, signals[SIG_STATE_CHANGED],
-				0, PURPLE_MEDIA_STATE_NEW,
-				session->id, NULL);
-	}
-
-	if (!g_list_find_custom(media->priv->participants,
-			who, (GCompareFunc)strcmp)) {
-		media->priv->participants = g_list_prepend(
-				media->priv->participants, g_strdup(who));
-
-		g_signal_emit(media, signals[SIG_STATE_CHANGED], 0,
-				PURPLE_MEDIA_STATE_NEW, NULL, who);
-	}
-
-	if (purple_media_get_stream(media, sess_id, who) == NULL) {
-		purple_media_insert_stream(session, who, initiator);
-
-		g_signal_emit(media, signals[SIG_STATE_CHANGED],
-				0, PURPLE_MEDIA_STATE_NEW,
-				session->id, who);
-	}
-
-	return TRUE;
-}
-
-PurpleMediaManager *
-purple_media_get_manager(PurpleMedia *media)
-{
-	PurpleMediaManager *ret;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	g_object_get(media, "manager", &ret, NULL);
-	return ret;
-}
-
-PurpleMediaSessionType
-purple_media_get_session_type(PurpleMedia *media, const gchar *sess_id)
-{
-	PurpleMediaSession *session;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), PURPLE_MEDIA_NONE);
-	session = purple_media_get_session(media, sess_id);
-	return session->type;
-}
-
-/* XXX: Should wait until codecs-ready is TRUE before using this function */
-GList *
-purple_media_get_codecs(PurpleMedia *media, const gchar *sess_id)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-
-	return purple_media_backend_get_codecs(media->priv->backend, sess_id);
-}
-
-GList *
-purple_media_get_local_candidates(PurpleMedia *media, const gchar *sess_id,
-                                  const gchar *participant)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-
-	return purple_media_backend_get_local_candidates(media->priv->backend,
-			sess_id, participant);
-}
-
-void
-purple_media_add_remote_candidates(PurpleMedia *media, const gchar *sess_id,
-                                   const gchar *participant,
-                                   GList *remote_candidates)
-{
-	PurpleMediaStream *stream;
-
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-	stream = purple_media_get_stream(media, sess_id, participant);
-
-	if (stream == NULL) {
-		purple_debug_error("media",
-				"purple_media_add_remote_candidates: "
-				"couldn't find stream %s %s.\n",
-				sess_id ? sess_id : "(null)",
-				participant ? participant : "(null)");
-		return;
-	}
-
-	stream->remote_candidates = g_list_concat(stream->remote_candidates,
-			purple_media_candidate_list_copy(remote_candidates));
-
-	purple_media_backend_add_remote_candidates(media->priv->backend,
-			sess_id, participant, remote_candidates);
-}
-
-GList *
-purple_media_get_active_local_candidates(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant)
-{
-	PurpleMediaStream *stream;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	stream = purple_media_get_stream(media, sess_id, participant);
-	return purple_media_candidate_list_copy(
-			stream->active_local_candidates);
-}
-
-GList *
-purple_media_get_active_remote_candidates(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant)
-{
-	PurpleMediaStream *stream;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	stream = purple_media_get_stream(media, sess_id, participant);
-	return purple_media_candidate_list_copy(
-			stream->active_remote_candidates);
-}
-
-gboolean
-purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id,
-                               const gchar *participant, GList *codecs)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	return purple_media_backend_set_remote_codecs(media->priv->backend,
-			sess_id, participant, codecs);
-}
-
-gboolean
-purple_media_candidates_prepared(PurpleMedia *media,
-		const gchar *session_id, const gchar *participant)
-{
-	GList *streams;
-	gboolean prepared = TRUE;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	streams = purple_media_get_streams(media, session_id, participant);
-
-	for (; streams; streams = g_list_delete_link(streams, streams)) {
-		PurpleMediaStream *stream = streams->data;
-		if (stream->candidates_prepared == FALSE) {
-			g_list_free(streams);
-			prepared = FALSE;
-			break;
-		}
-	}
-
-	return prepared;
-}
-
-gboolean
-purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMediaCodec *codec)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	return purple_media_backend_set_send_codec(
-			media->priv->backend, sess_id, codec);
-}
-
-gboolean
-purple_media_set_encryption_parameters(PurpleMedia *media, const gchar *sess_id,
-		const gchar *cipher, const gchar *auth,
-		const gchar *key, gsize key_len)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-	return purple_media_backend_set_encryption_parameters(media->priv->backend,
-			sess_id, cipher, auth, key, key_len);
-}
-
-gboolean
-purple_media_set_decryption_parameters(PurpleMedia *media, const gchar *sess_id,
-		const gchar *participant, const gchar *cipher,
-		const gchar *auth, const gchar *key, gsize key_len)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-	return purple_media_backend_set_decryption_parameters(media->priv->backend,
-			sess_id, participant, cipher, auth, key, key_len);
-}
-
-gboolean
-purple_media_set_require_encryption(PurpleMedia *media, const gchar *sess_id,
-                const gchar *participant, gboolean require_encryption)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-	return purple_media_backend_set_require_encryption(media->priv->backend,
-			sess_id, participant, require_encryption);
-}
-
-gboolean
-purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	return purple_media_backend_codecs_ready(
-			media->priv->backend, sess_id);
-}
-
-gboolean
-purple_media_set_send_rtcp_mux(PurpleMedia *media, const gchar *sess_id,
-                               const gchar *participant, gboolean send_rtcp_mux)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	return purple_media_backend_set_send_rtcp_mux(media->priv->backend,
-			sess_id, participant, send_rtcp_mux);
-}
-
-gboolean
-purple_media_is_initiator(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	if (sess_id == NULL && participant == NULL)
-		return media->priv->initiator;
-	else if (sess_id != NULL && participant == NULL) {
-		PurpleMediaSession *session =
-				purple_media_get_session(media, sess_id);
-		return session != NULL ? session->initiator : FALSE;
-	} else if (sess_id != NULL && participant != NULL) {
-		PurpleMediaStream *stream = purple_media_get_stream(
-				media, sess_id, participant);
-		return stream != NULL ? stream->initiator : FALSE;
-	}
-
-	return FALSE;
-}
-
-gboolean
-purple_media_accepted(PurpleMedia *media, const gchar *sess_id,
-		const gchar *participant)
-{
-	gboolean accepted = TRUE;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	if (sess_id == NULL && participant == NULL) {
-		GList *streams = media->priv->streams;
-
-		for (; streams; streams = g_list_next(streams)) {
-			PurpleMediaStream *stream = streams->data;
-			if (stream->accepted == FALSE) {
-				accepted = FALSE;
-				break;
-			}
-		}
-	} else if (sess_id != NULL && participant == NULL) {
-		GList *streams = purple_media_get_streams(media, sess_id, NULL);
-		for (; streams; streams = g_list_delete_link(streams, streams)) {
-			PurpleMediaStream *stream = streams->data;
-			if (stream->accepted == FALSE) {
-				g_list_free(streams);
-				accepted = FALSE;
-				break;
-			}
-		}
-	} else if (sess_id != NULL && participant != NULL) {
-		PurpleMediaStream *stream = purple_media_get_stream(
-				media, sess_id, participant);
-		if (stream == NULL || stream->accepted == FALSE) {
-			accepted = FALSE;
-		}
-	}
-
-	return accepted;
-}
-
-void
-purple_media_set_input_volume(PurpleMedia *media,
-                              G_GNUC_UNUSED const char *session_id,
-                              G_GNUC_UNUSED double level)
-{
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-}
-
-void
-purple_media_set_output_volume(PurpleMedia *media,
-                               G_GNUC_UNUSED const char *session_id,
-                               G_GNUC_UNUSED const char *participant,
-                               G_GNUC_UNUSED double level)
-{
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-}
-
-gulong
-purple_media_set_output_window(PurpleMedia *media, const gchar *session_id,
-		const gchar *participant)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	return purple_media_manager_set_output_window(media->priv->manager,
-			media, session_id, participant);
-}
-
-void
-purple_media_remove_output_windows(PurpleMedia *media)
-{
-	GList *iter = media->priv->streams;
-	for (; iter; iter = g_list_next(iter)) {
-		PurpleMediaStream *stream = iter->data;
-		purple_media_manager_remove_output_windows(
-				media->priv->manager, media,
-				stream->session->id, stream->participant);
-	}
-
-	iter = purple_media_get_session_ids(media);
-	for (; iter; iter = g_list_delete_link(iter, iter)) {
-		gchar *session_name = iter->data;
-		purple_media_manager_remove_output_windows(
-				media->priv->manager, media,
-				session_name, NULL);
-	}
-}
-
-GstElement *
-purple_media_get_tee(PurpleMedia *media, G_GNUC_UNUSED const char *session_id,
-                     G_GNUC_UNUSED const char *participant)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-
-	return NULL;
-}
-
-gboolean
-purple_media_send_dtmf(PurpleMedia *media, const gchar *session_id,
-		gchar dtmf, guint8 volume, guint16 duration)
-{
-	PurpleMediaBackendInterface *backend_iface = NULL;
-
-	if (media) {
-		backend_iface = PURPLE_MEDIA_BACKEND_GET_INTERFACE(media->priv->backend);
-	}
-
-	if (dtmf == 'a') {
-		dtmf = 'A';
-	} else if (dtmf == 'b') {
-		dtmf = 'B';
-	} else if (dtmf == 'c') {
-		dtmf = 'C';
-	} else if (dtmf == 'd') {
-		dtmf = 'D';
-	}
-
-	g_return_val_if_fail(strchr("0123456789ABCD#*", dtmf), FALSE);
-
-	if (backend_iface && backend_iface->send_dtmf
-		&& backend_iface->send_dtmf(media->priv->backend,
-				session_id, dtmf, volume, duration))
-	{
-		return TRUE;
-	}
-
-	return FALSE;
-}
diff --git a/libpurple/media/backend-iface.h b/libpurple/media/backend-iface.h
deleted file mode 100644
--- a/libpurple/media/backend-iface.h
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_MEDIA_BACKEND_IFACE_H
-#define PURPLE_MEDIA_BACKEND_IFACE_H
-
-#include "codec.h"
-#include "enum-types.h"
-#include "media.h"
-#include "purpleversion.h"
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define PURPLE_MEDIA_TYPE_BACKEND		(purple_media_backend_get_type())
-#define PURPLE_MEDIA_IS_BACKEND(obj)		(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_MEDIA_TYPE_BACKEND))
-#define PURPLE_MEDIA_BACKEND(obj)		(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_MEDIA_TYPE_BACKEND, PurpleMediaBackend))
-#define PURPLE_MEDIA_BACKEND_GET_INTERFACE(inst)(G_TYPE_INSTANCE_GET_INTERFACE((inst), PURPLE_MEDIA_TYPE_BACKEND, PurpleMediaBackendInterface))
-
-/**
- * PurpleMediaBackend:
- *
- * A placeholder to represent any media backend
- *
- * Since: 2.6
- */
-typedef struct _PurpleMediaBackend PurpleMediaBackend;
-
-typedef struct _PurpleMediaBackendInterface PurpleMediaBackendInterface;
-
-struct _PurpleMediaBackendInterface
-{
-	/*< private >*/
-	GTypeInterface parent_iface; /* The parent iface class */
-
-	/*< public >*/
-	/* Implementable functions called with purple_media_backend_* */
-	gboolean (*add_stream) (PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *who,
-		PurpleMediaSessionType type, gboolean initiator,
-		const gchar *transmitter, GHashTable *params);
-
-	void (*add_remote_candidates) (PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		GList *remote_candidates);
-	gboolean (*codecs_ready) (PurpleMediaBackend *self,
-		const gchar *sess_id);
-	GList *(*get_codecs) (PurpleMediaBackend *self,
-		const gchar *sess_id);
-	GList *(*get_local_candidates) (PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant);
-	gboolean (*set_remote_codecs) (PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		GList *codecs);
-	gboolean (*set_send_codec) (PurpleMediaBackend *self,
-		const gchar *sess_id, PurpleMediaCodec *codec);
-	gboolean (*set_encryption_parameters) (PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *cipher,
-		const gchar *auth, const gchar *key, gsize key_len);
-	gboolean (*set_decryption_parameters) (PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		const gchar *cipher, const gchar *auth,
-		const gchar *key, gsize key_len);
-	gboolean (*set_require_encryption) (PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		gboolean require_encryption);
-	void (*set_params) (PurpleMediaBackend *self, GHashTable *params);
-	const gchar **(*get_available_params) (void);
-	gboolean (*send_dtmf) (PurpleMediaBackend *self,
-		const gchar *sess_id, gchar dtmf, guint8 volume,
-		guint16 duration);
-	gboolean (*set_send_rtcp_mux) (PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant, gboolean send_rtcp_mux);
-};
-
-/**
- * purple_media_backend_get_type:
- *
- * Gets the media backend's GType.
- *
- * Returns: The media backend's GType.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-GType purple_media_backend_get_type(void);
-
-/**
- * purple_media_backend_add_stream:
- * @self: The backend to add the stream to.
- * @sess_id: The session id of the stream to add.
- * @who: The remote participant of the stream to add.
- * @type: The media type and direction of the stream to add.
- * @initiator: True if the local user initiated the stream.
- * @transmitter: The string id of the tranmsitter to use.
- * @params: (element-type utf8 GValue) (transfer none): The additional
- *          parameters to pass when creating the stream.
- *
- * Creates and adds a stream to the media backend.
- *
- * Returns: True if the stream was successfully created, otherwise False.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-gboolean purple_media_backend_add_stream(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *who, PurpleMediaSessionType type,
-		gboolean initiator, const gchar *transmitter, GHashTable *params);
-
-/**
- * purple_media_backend_add_remote_candidates:
- * @self: The backend the stream is in.
- * @sess_id: The session id associated with the stream.
- * @participant: The participant associated with the stream.
- * @remote_candidates: (element-type PurpleMediaCandidate): The list of remote candidates to add.
- *
- * Add remote candidates to a stream.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-void purple_media_backend_add_remote_candidates(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		GList *remote_candidates);
-
-/**
- * purple_media_backend_codecs_ready:
- * @self: The media backend the session is in.
- * @sess_id: The session id of the session to check.
- *
- * Get whether or not a session's codecs are ready.
- *
- * A codec is ready if all of the attributes and additional
- * parameters have been collected.
- *
- * Returns: True if the codecs are ready, otherwise False.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-gboolean purple_media_backend_codecs_ready(PurpleMediaBackend *self,
-		const gchar *sess_id);
-
-/**
- * purple_media_backend_get_codecs:
- * @self: The media backend the session is in.
- * @sess_id: The session id of the session to use.
- *
- * Gets the codec intersection list for a session.
- *
- * The intersection list consists of all codecs that are compatible
- * between the local and remote software.
- *
- * Returns: (transfer full) (element-type PurpleMediaCodec): The codec intersection list.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-GList *purple_media_backend_get_codecs(PurpleMediaBackend *self,
-		const gchar *sess_id);
-
-/**
- * purple_media_backend_get_local_candidates:
- * @self: The media backend the stream is in.
- * @sess_id: The session id associated with the stream.
- * @participant: The participant associated with the stream.
- *
- * Gets the list of local candidates for a stream.
- *
- * Returns: (transfer full) (element-type PurpleMediaCandidate): The list of
- *          local candidates.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-GList *purple_media_backend_get_local_candidates(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant);
-
-/**
- * purple_media_backend_set_remote_codecs:
- * @self: The media backend the stream is in.
- * @sess_id: The session id the stream is associated with.
- * @participant: The participant the stream is associated with.
- * @codecs: (element-type PurpleMediaCodec): The list of remote codecs to set.
- *
- * Sets the remote codecs on a stream.
- *
- * Returns: True if the remote codecs were set successfully, otherwise False.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-gboolean purple_media_backend_set_remote_codecs(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		GList *codecs);
-
-/**
- * purple_media_backend_set_send_codec:
- * @self: The media backend the session is in.
- * @sess_id: The session id of the session to set the codec for.
- * @codec: The codec to set.
- *
- * Sets which codec format to send media content in for a session.
- *
- * Returns: True if set successfully, otherwise False.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-gboolean purple_media_backend_set_send_codec(PurpleMediaBackend *self,
-		const gchar *sess_id, PurpleMediaCodec *codec);
-
-/**
- * purple_media_backend_set_encryption_parameters:
- * @self: The media backend the session is in.
- * @sess_id: The session id of the session to set parameters of.
- * @cipher: The cipher to use to encrypt our media in the session.
- * @auth: The algorithm to use to compute authentication codes for our media
- *        frames.
- * @key: The encryption key.
- * @key_len: Byte length of the encryption key.
- *
- * Sets the encryption parameters of our media in the session.
- *
- * Returns: %TRUE if the settings were successfully applied, otherwise %FALSE.
- *
- * Since: 2.11
- */
-PURPLE_AVAILABLE_IN_2_11
-gboolean purple_media_backend_set_encryption_parameters(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *cipher,
-		const gchar *auth, const gchar *key, gsize key_len);
-
-/**
- * purple_media_backend_set_decryption_parameters:
- * @self: The media backend the session is in.
- * @sess_id: The session id of the session to set parameters of.
- * @participant: The participant of the session to set parameters of.
- * @cipher: The cipher to use to decrypt media coming from this session's
- *          participant.
- * @auth: The algorithm to use for authentication of the media coming from
- *        the session's participant.
- * @key: The decryption key.
- * @key_len: Byte length of the decryption key.
- *
- * Sets the decryption parameters for a session participant's media.
- *
- * Returns: %TRUE if the change was successful.
- *
- * Since: 2.11
- */
-PURPLE_AVAILABLE_IN_2_11
-gboolean purple_media_backend_set_decryption_parameters(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		const gchar *cipher, const gchar *auth,
-		const gchar *key, gsize key_len);
-
-/**
- * purple_media_backend_set_require_encryption:
- * @self: The media object to find the session in.
- * @sess_id: The id of the session to set parameters of.
- * @participant: The participant of the session to set parameters of.
- * @require_encryption: TRUE if the media requires encryption.
- *
- * Sets whether a session participant's media requires encryption.
- *
- * Returns: %TRUE if the change was successful.
- *
- * Since: 2.14
- */
-PURPLE_AVAILABLE_IN_2_14
-gboolean purple_media_backend_set_require_encryption(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		gboolean require_encryption);
-
-/**
- * purple_media_backend_set_params:
- * @self: The media backend to set the parameters on.
- * @params: (element-type utf8 GObject.Value) (transfer none): Hash table of
- *          parameters to pass to the backend.
- *
- * Sets various optional parameters of the media backend.
- *
- * Since: 2.8
- */
-PURPLE_AVAILABLE_IN_2_8
-void purple_media_backend_set_params(PurpleMediaBackend *self,
-		GHashTable *params);
-
-/**
- * purple_media_backend_get_available_params:
- * @self: The media backend
- *
- * Gets the list of optional parameters supported by the media backend.
- * The list should NOT be freed.
- *
- * Returns: (transfer none): NULL-terminated array of names of supported
- *          parameters.
- *
- * Since: 2.8
- */
-PURPLE_AVAILABLE_IN_2_8
-const gchar **purple_media_backend_get_available_params(PurpleMediaBackend *self);
-
-/**
- * purple_media_backend_set_send_rtcp_mux:
- * @self: The media backend the session is in.
- * @sess_id: The session id of the session to set the rtcp-mux option to
- * @participant: The participant the stream is associated with.
- * @send_rtcp_mux: Whether or not to enable rtcp-mux
- *
- * Controls whether or not the RTCP should be muxed with the RTP
- *
- * Returns: True if set successfully, otherwise False.
- *
- * Since: 2.11
- */
-PURPLE_AVAILABLE_IN_2_11
-gboolean purple_media_backend_set_send_rtcp_mux(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant, gboolean send_rtcp_mux);
-
-
-G_END_DECLS
-
-#endif /* PURPLE_MEDIA_BACKEND_IFACE_H */
diff --git a/libpurple/media/backend-iface.c b/libpurple/media/backend-iface.c
deleted file mode 100644
--- a/libpurple/media/backend-iface.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "backend-iface.h"
-
-enum {
-	SIG_ERROR,
-	SIG_CANDIDATES_PREPARED,
-	SIG_CODECS_CHANGED,
-	SIG_NEW_CANDIDATE,
-	SIG_ACTIVE_CANDIDATE_PAIR,
-	N_SIGNALS,
-};
-
-static guint signals[N_SIGNALS] = {0, };
-
-static void
-purple_media_backend_base_init(gpointer iface)
-{
-	static gboolean is_initialized = FALSE;
-
-	if (is_initialized) {
-		return;
-	}
-
-	/**
-	 * PurpleMediaBackend:conference-type:
-	 *
-	 * The type of the conference.
-	 */
-	g_object_interface_install_property(iface,
-		g_param_spec_string("conference-type",
-			"Conference Type",
-			"The type of conference that this backend "
-			"has been created to provide.",
-			NULL,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaBackend:media:
-	 *
-	 * The media object that this back end is bound to.
-	 */
-	g_object_interface_install_property(iface,
-		g_param_spec_object(
-			"media", "Purple Media",
-			"The media object that this backend is bound to.",
-			PURPLE_TYPE_MEDIA,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaBackend::error:
-	 * @backend: The backend instance.
-	 * @message: The error message.
-	 *
-	 * Emitted when the backend has encountered an error.
-	 */
-	signals[SIG_ERROR] = g_signal_new("error",
-			G_TYPE_FROM_CLASS(iface),
-			G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-			G_TYPE_NONE, 1, G_TYPE_STRING);
-
-	/**
-	 * PurpleMediaBackend::candidates-prepared:
-	 * @backend: The backend instance.
-	 * @session_id: The session id.
-	 * @name: The name.
-	 *
-	 * Emitted when the candidates have been prepared.
-	 */
-	signals[SIG_CANDIDATES_PREPARED] = g_signal_new("candidates-prepared",
-			G_TYPE_FROM_CLASS(iface),
-			G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-			G_TYPE_NONE, 2, G_TYPE_STRING,
-			G_TYPE_STRING);
-
-	/**
-	 * PurpleMediaBackend::codecs-changed:
-	 * @backend: The backend instance.
-	 * @session_id: The session id.
-	 *
-	 * Emitted when the codecs have changed.
-	 */
-	signals[SIG_CODECS_CHANGED] = g_signal_new("codecs-changed",
-			G_TYPE_FROM_CLASS(iface),
-			G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-			G_TYPE_NONE, 1, G_TYPE_STRING);
-
-	/**
-	 * PurpleMediaBackend::new-candidate:
-	 * @backend: The backend instance.
-	 * @session_id: The session id.
-	 * @participant: The participant.
-	 * @candidate: The new candidate.
-	 *
-	 * Emitted when a new media candidate is available.
-	 */
-	signals[SIG_NEW_CANDIDATE] = g_signal_new("new-candidate",
-			G_TYPE_FROM_CLASS(iface),
-			G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-			G_TYPE_NONE, 3, G_TYPE_POINTER,
-			G_TYPE_POINTER, PURPLE_MEDIA_TYPE_CANDIDATE);
-
-	/**
-	 * PurpleMediaBackend::active-candidate-pair:
-	 * @backend: The backend instance.
-	 * @session_id: The session id.
-	 * @participant: The participant.
-	 * @candidate1: The first candidate.
-	 * @candidate2: The second candidate.
-	 *
-	 * This is currently not emitted any, so I'd be guessing...
-	 */
-	signals[SIG_ACTIVE_CANDIDATE_PAIR] = g_signal_new("active-candidate-pair",
-			G_TYPE_FROM_CLASS(iface),
-			G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
-			G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING,
-			PURPLE_MEDIA_TYPE_CANDIDATE,
-			PURPLE_MEDIA_TYPE_CANDIDATE);
-
-	is_initialized = TRUE;
-}
-
-GType
-purple_media_backend_get_type(void)
-{
-	static GType iface_type = 0;
-	if (iface_type == 0) {
-		static const GTypeInfo info = {
-			sizeof(PurpleMediaBackendInterface),
-			purple_media_backend_base_init,
-			NULL,
-			NULL,
-			NULL,
-			NULL,
-			0,
-			0,
-			NULL,
-			NULL
-		};
-
-		iface_type = g_type_register_static (G_TYPE_INTERFACE,
-				"PurpleMediaBackend", &info, 0);
-	}
-
-	return iface_type;
-}
-
-gboolean
-purple_media_backend_add_stream(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *who, PurpleMediaSessionType type,
-		gboolean initiator, const gchar *transmitter, GHashTable *params)
-{
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND(self), FALSE);
-	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->add_stream(self,
-			sess_id, who, type, initiator, transmitter, params);
-}
-
-void
-purple_media_backend_add_remote_candidates(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		GList *remote_candidates)
-{
-	g_return_if_fail(PURPLE_MEDIA_IS_BACKEND(self));
-	PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->add_remote_candidates(self,
-			sess_id, participant, remote_candidates);
-}
-
-gboolean
-purple_media_backend_codecs_ready(PurpleMediaBackend *self,
-		const gchar *sess_id)
-{
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND(self), FALSE);
-	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->codecs_ready(self,
-			sess_id);
-}
-
-GList *
-purple_media_backend_get_codecs(PurpleMediaBackend *self,
-		const gchar *sess_id)
-{
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND(self), NULL);
-	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->get_codecs(self,
-			sess_id);
-}
-
-GList *
-purple_media_backend_get_local_candidates(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant)
-{
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND(self), NULL);
-	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->
-			get_local_candidates(self,
-			sess_id, participant);
-}
-
-gboolean
-purple_media_backend_set_remote_codecs(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		GList *codecs)
-{
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND(self), FALSE);
-	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->set_remote_codecs(
-			self, sess_id, participant, codecs);
-}
-
-gboolean
-purple_media_backend_set_send_codec(PurpleMediaBackend *self,
-		const gchar *sess_id, PurpleMediaCodec *codec)
-{
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND(self), FALSE);
-	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->set_send_codec(self,
-			sess_id, codec);
-}
-
-gboolean
-purple_media_backend_set_encryption_parameters(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *cipher,
-		const gchar *auth, const gchar *key, gsize key_len)
-{
-	PurpleMediaBackendInterface *backend_iface;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND(self), FALSE);
-	backend_iface = PURPLE_MEDIA_BACKEND_GET_INTERFACE(self);
-	g_return_val_if_fail(backend_iface->set_encryption_parameters, FALSE);
-	return backend_iface->set_encryption_parameters(self,
-			sess_id, cipher, auth, key, key_len);
-}
-
-gboolean
-purple_media_backend_set_decryption_parameters(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		const gchar *cipher, const gchar *auth,
-		const gchar *key, gsize key_len)
-{
-	PurpleMediaBackendInterface *backend_iface;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND(self), FALSE);
-	backend_iface = PURPLE_MEDIA_BACKEND_GET_INTERFACE(self);
-	g_return_val_if_fail(backend_iface->set_decryption_parameters, FALSE);
-	return backend_iface->set_decryption_parameters(self,
-			sess_id, participant, cipher, auth, key, key_len);
-}
-
-gboolean
-purple_media_backend_set_require_encryption(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant,
-		gboolean require_encryption)
-{
-	PurpleMediaBackendInterface *backend_iface;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND(self), FALSE);
-	backend_iface = PURPLE_MEDIA_BACKEND_GET_INTERFACE(self);
-
-	if (!backend_iface->set_require_encryption) {
-		return FALSE;
-	}
-
-	return backend_iface->set_require_encryption(self,
-			sess_id, participant, require_encryption);
-}
-
-void
-purple_media_backend_set_params(PurpleMediaBackend *self, GHashTable *params)
-{
-	g_return_if_fail(PURPLE_MEDIA_IS_BACKEND(self));
-	PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->set_params(self, params);
-}
-
-const gchar **
-purple_media_backend_get_available_params(PurpleMediaBackend *self)
-{
-	static const gchar *NULL_ARRAY[] = { NULL };
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND(self), NULL_ARRAY);
-	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->get_available_params();
-}
-
-gboolean
-purple_media_backend_set_send_rtcp_mux(PurpleMediaBackend *self,
-		const gchar *sess_id, const gchar *participant, gboolean send_rtcp_mux)
-{
-	PurpleMediaBackendInterface *backend_iface;
-
-	g_return_val_if_fail(PURPLE_MEDIA_IS_BACKEND(self), FALSE);
-	backend_iface = PURPLE_MEDIA_BACKEND_GET_INTERFACE(self);
-	g_return_val_if_fail(backend_iface->set_send_rtcp_mux, FALSE);
-	return backend_iface->set_send_rtcp_mux(self,
-			sess_id, participant, send_rtcp_mux);
-}
diff --git a/libpurple/media/candidate.h b/libpurple/media/candidate.h
deleted file mode 100644
--- a/libpurple/media/candidate.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_MEDIA_CANDIDATE_H
-#define PURPLE_MEDIA_CANDIDATE_H
-
-#include "enum-types.h"
-
-#include <glib-object.h>
-
-#include "purpleversion.h"
-
-G_BEGIN_DECLS
-
-/**
- * PURPLE_MEDIA_TYPE_CANDIDATE:
- *
- * The standard _get_type macro for #PurpleMediaCandidate.
- *
- * Since: 3.0
- */
-#define PURPLE_MEDIA_TYPE_CANDIDATE  purple_media_candidate_get_type()
-
-/**
- * purple_media_candidate_get_type:
- *
- * Gets the type of the media candidate structure.
- *
- * Returns: The media canditate's GType
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-G_DECLARE_FINAL_TYPE(PurpleMediaCandidate, purple_media_candidate,
-                     PURPLE_MEDIA, CANDIDATE, GObject)
-
-/**
- * purple_media_candidate_new:
- * @foundation: The foundation of the candidate.
- * @component_id: The component this candidate is for.
- * @type: The type of candidate.
- * @proto: The protocol this component is for.
- * @ip: The IP address of this component.
- * @port: The network port.
- *
- * Creates a PurpleMediaCandidate instance.
- *
- * Returns: The newly created PurpleMediaCandidate instance.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMediaCandidate *purple_media_candidate_new(
-		const gchar *foundation, guint component_id,
-		PurpleMediaCandidateType type,
-		PurpleMediaNetworkProtocol proto,
-		const gchar *ip, guint port);
-
-/**
- * purple_media_candidate_copy:
- * @candidate: The candidate to copy.
- *
- * Copies a PurpleMediaCandidate.
- *
- * Returns: (transfer full): The copy of the PurpleMediaCandidate.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-PurpleMediaCandidate *purple_media_candidate_copy(
-		PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_list_copy:
- * @candidates: (element-type PurpleMediaCandidate) (transfer none): The list
- *              of candidates to be copied.
- *
- * Copies a GList of PurpleMediaCandidate and its contents.
- *
- * Returns: (element-type PurpleMediaCandidate) (transfer full): The copy of
- *          the candidate list.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GList *purple_media_candidate_list_copy(GList *candidates);
-
-/**
- * purple_media_candidate_list_free:
- * @candidates: (element-type PurpleMediaCandidate) (transfer full): The list
- *              of candidates to be freed.
- *
- * Frees a GList of PurpleMediaCandidate and its contents.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_candidate_list_free(GList *candidates);
-
-/**
- * purple_media_candidate_get_foundation:
- * @candidate: The candidate to get the foundation from.
- *
- * Gets the foundation (identifier) from the candidate.
- *
- * Returns: The foundation.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gchar *purple_media_candidate_get_foundation(PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_get_component_id:
- * @candidate: The candidate to get the component id from.
- *
- * Gets the component id (rtp or rtcp)
- *
- * Returns: The component id.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-guint purple_media_candidate_get_component_id(PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_get_ip:
- * @candidate: The candidate to get the IP address from.
- *
- * Gets the IP address.
- *
- * Returns: The IP address.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gchar *purple_media_candidate_get_ip(PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_get_port:
- * @candidate: The candidate to get the port from.
- *
- * Gets the port.
- *
- * Returns: The port.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-guint16 purple_media_candidate_get_port(PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_get_base_ip:
- * @candidate: The candidate to get the base IP address from.
- *
- * Gets the base (internal) IP address.
- * This can be NULL.
- *
- * Returns: The base IP address.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gchar *purple_media_candidate_get_base_ip(PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_get_base_port:
- * @candidate: The candidate to get the base port.
- *
- * Gets the base (internal) port.
- * Invalid if the base IP is NULL.
- *
- * Returns: The base port.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-guint16 purple_media_candidate_get_base_port(PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_get_protocol:
- * @candidate: The candidate to get the protocol from.
- *
- * Gets the protocol (TCP or UDP).
- *
- * Returns: The protocol.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMediaNetworkProtocol purple_media_candidate_get_protocol(
-		PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_get_priority:
- * @candidate: The candidate to get the priority from.
- *
- * Gets the priority.
- *
- * Returns: The priority.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-guint32 purple_media_candidate_get_priority(PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_get_candidate_type:
- * @candidate: The candidate to get the candidate type from.
- *
- * Gets the candidate type.
- *
- * Returns: The candidate type.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMediaCandidateType purple_media_candidate_get_candidate_type(
-		PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_get_username:
- * @candidate: The candidate to get the username from.
- *
- * Gets the username.
- * This can be NULL. It depends on the transmission type.
- *
- * Returns: The username.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gchar *purple_media_candidate_get_username(PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_get_password:
- * @candidate: The candidate to get the password from.
- *
- * Gets the password.
- *
- * This can be NULL. It depends on the transmission type.
- *
- * Returns: The password.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gchar *purple_media_candidate_get_password(PurpleMediaCandidate *candidate);
-
-/**
- * purple_media_candidate_get_ttl:
- * @candidate: The candidate to get the TTL from.
- *
- * Gets the TTL.
- *
- * Returns: The TTL.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-guint purple_media_candidate_get_ttl(PurpleMediaCandidate *candidate);
-
-G_END_DECLS
-
-#endif /* PURPLE_MEDIA_CANDIDATE_H */
diff --git a/libpurple/media/candidate.c b/libpurple/media/candidate.c
deleted file mode 100644
--- a/libpurple/media/candidate.c
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "candidate.h"
-
-/**
- * PurpleMediaCandidate:
- *
- * An opaque structure representing a network candidate (IP Address and port
- * pair).
- */
-struct _PurpleMediaCandidate
-{
-	GObject parent;
-};
-
-typedef struct
-{
-	gchar *foundation;
-	guint component_id;
-	gchar *ip;
-	guint16 port;
-	gchar *base_ip;
-	guint16 base_port;
-	PurpleMediaNetworkProtocol proto;
-	guint32 priority;
-	PurpleMediaCandidateType type;
-	gchar *username;
-	gchar *password;
-	guint ttl;
-} PurpleMediaCandidatePrivate;
-
-enum {
-	PROP_0,
-	PROP_FOUNDATION,
-	PROP_COMPONENT_ID,
-	PROP_IP,
-	PROP_PORT,
-	PROP_BASE_IP,
-	PROP_BASE_PORT,
-	PROP_PROTOCOL,
-	PROP_PRIORITY,
-	PROP_TYPE,
-	PROP_USERNAME,
-	PROP_PASSWORD,
-	PROP_TTL,
-	N_PROPERTIES,
-};
-
-G_DEFINE_FINAL_TYPE_WITH_PRIVATE(PurpleMediaCandidate, purple_media_candidate,
-                                 G_TYPE_OBJECT)
-
-static void
-purple_media_candidate_init(PurpleMediaCandidate *info)
-{
-	PurpleMediaCandidatePrivate *priv =
-			purple_media_candidate_get_instance_private(info);
-	priv->foundation = NULL;
-	priv->component_id = 0;
-	priv->ip = NULL;
-	priv->port = 0;
-	priv->base_ip = NULL;
-	priv->proto = PURPLE_MEDIA_NETWORK_PROTOCOL_UDP;
-	priv->priority = 0;
-	priv->type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
-	priv->username = NULL;
-	priv->password = NULL;
-	priv->ttl = 0;
-}
-
-static void
-purple_media_candidate_finalize(GObject *info)
-{
-	PurpleMediaCandidatePrivate *priv =
-			purple_media_candidate_get_instance_private(
-					PURPLE_MEDIA_CANDIDATE(info));
-
-	g_free(priv->foundation);
-	g_free(priv->ip);
-	g_free(priv->base_ip);
-	g_free(priv->username);
-	g_free(priv->password);
-
-	G_OBJECT_CLASS(purple_media_candidate_parent_class)->finalize(info);
-}
-
-static void
-purple_media_candidate_set_property (GObject *object, guint prop_id,
-		const GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaCandidatePrivate *priv;
-
-	priv = purple_media_candidate_get_instance_private(
-			PURPLE_MEDIA_CANDIDATE(object));
-
-	switch (prop_id) {
-		case PROP_FOUNDATION:
-			g_free(priv->foundation);
-			priv->foundation = g_value_dup_string(value);
-			break;
-		case PROP_COMPONENT_ID:
-			priv->component_id = g_value_get_uint(value);
-			break;
-		case PROP_IP:
-			g_free(priv->ip);
-			priv->ip = g_value_dup_string(value);
-			break;
-		case PROP_PORT:
-			priv->port = g_value_get_uint(value);
-			break;
-		case PROP_BASE_IP:
-			g_free(priv->base_ip);
-			priv->base_ip = g_value_dup_string(value);
-			break;
-		case PROP_BASE_PORT:
-			priv->base_port = g_value_get_uint(value);
-			break;
-		case PROP_PROTOCOL:
-			priv->proto = g_value_get_enum(value);
-			break;
-		case PROP_PRIORITY:
-			priv->priority = g_value_get_uint(value);
-			break;
-		case PROP_TYPE:
-			priv->type = g_value_get_enum(value);
-			break;
-		case PROP_USERNAME:
-			g_free(priv->username);
-			priv->username = g_value_dup_string(value);
-			break;
-		case PROP_PASSWORD:
-			g_free(priv->password);
-			priv->password = g_value_dup_string(value);
-			break;
-		case PROP_TTL:
-			priv->ttl = g_value_get_uint(value);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(
-					object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_candidate_get_property (GObject *object, guint prop_id,
-		GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaCandidatePrivate *priv;
-
-	priv = purple_media_candidate_get_instance_private(
-			PURPLE_MEDIA_CANDIDATE(object));
-
-	switch (prop_id) {
-		case PROP_FOUNDATION:
-			g_value_set_string(value, priv->foundation);
-			break;
-		case PROP_COMPONENT_ID:
-			g_value_set_uint(value, priv->component_id);
-			break;
-		case PROP_IP:
-			g_value_set_string(value, priv->ip);
-			break;
-		case PROP_PORT:
-			g_value_set_uint(value, priv->port);
-			break;
-		case PROP_BASE_IP:
-			g_value_set_string(value, priv->base_ip);
-			break;
-		case PROP_BASE_PORT:
-			g_value_set_uint(value, priv->base_port);
-			break;
-		case PROP_PROTOCOL:
-			g_value_set_enum(value, priv->proto);
-			break;
-		case PROP_PRIORITY:
-			g_value_set_uint(value, priv->priority);
-			break;
-		case PROP_TYPE:
-			g_value_set_enum(value, priv->type);
-			break;
-		case PROP_USERNAME:
-			g_value_set_string(value, priv->username);
-			break;
-		case PROP_PASSWORD:
-			g_value_set_string(value, priv->password);
-			break;
-		case PROP_TTL:
-			g_value_set_uint(value, priv->ttl);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(
-					object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_candidate_class_init(PurpleMediaCandidateClass *klass)
-{
-	GObjectClass *gobject_class = (GObjectClass*)klass;
-
-	gobject_class->finalize = purple_media_candidate_finalize;
-	gobject_class->set_property = purple_media_candidate_set_property;
-	gobject_class->get_property = purple_media_candidate_get_property;
-
-	/**
-	 * PurpleMediaCandidate:foundation:
-	 *
-	 * The foundation of the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_FOUNDATION,
-			g_param_spec_string("foundation",
-			"Foundation",
-			"The foundation of the candidate.",
-			NULL,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaCandidate:component-id:
-	 *
-	 * The component id of the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_COMPONENT_ID,
-			g_param_spec_uint("component-id",
-			"Component ID",
-			"The component id of the candidate.",
-			0, G_MAXUINT, 0,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaCandidate:ip:
-	 *
-	 * The IP address of the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_IP,
-			g_param_spec_string("ip",
-			"IP Address",
-			"The IP address of the candidate.",
-			NULL,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaCandidate:port:
-	 *
-	 * The port of the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_PORT,
-			g_param_spec_uint("port",
-			"Port",
-			"The port of the candidate.",
-			0, G_MAXUINT16, 0,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaCandidate:base-ip:
-	 *
-	 * The internal IP address of the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_BASE_IP,
-			g_param_spec_string("base-ip",
-			"Base IP",
-			"The internal IP address of the candidate.",
-			NULL,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaCandidate:base-port:
-	 *
-	 * The internal port of the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_BASE_PORT,
-			g_param_spec_uint("base-port",
-			"Base Port",
-			"The internal port of the candidate.",
-			0, G_MAXUINT16, 0,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaCandidate:protocol:
-	 *
-	 * The protocol of the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_PROTOCOL,
-			g_param_spec_enum("protocol",
-			"Protocol",
-			"The protocol of the candidate.",
-			PURPLE_MEDIA_TYPE_NETWORK_PROTOCOL,
-			PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaCandidate:priority:
-	 *
-	 * The priority of the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_PRIORITY,
-			g_param_spec_uint("priority",
-			"Priority",
-			"The priority of the candidate.",
-			0, G_MAXUINT32, 0,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaCandidate:type:
-	 *
-	 * The type of the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_TYPE,
-			g_param_spec_enum("type",
-			"Type",
-			"The type of the candidate.",
-			PURPLE_MEDIA_TYPE_CANDIDATE_TYPE,
-			PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaCandidate:username:
-	 *
-	 * The username used to connect to the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_USERNAME,
-			g_param_spec_string("username",
-			"Username",
-			"The username used to connect to the candidate.",
-			NULL,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaCandidate:password:
-	 *
-	 * The password used to connect to the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_PASSWORD,
-			g_param_spec_string("password",
-			"Password",
-			"The password use to connect to the candidate.",
-			NULL,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaCandidate:ttl:
-	 *
-	 * The TTL of the candidate.
-	 */
-	g_object_class_install_property(gobject_class, PROP_TTL,
-			g_param_spec_uint("ttl",
-			"TTL",
-			"The TTL of the candidate.",
-			0, G_MAXUINT, 0,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-}
-
-PurpleMediaCandidate *
-purple_media_candidate_new(const gchar *foundation, guint component_id,
-		PurpleMediaCandidateType type,
-		PurpleMediaNetworkProtocol proto,
-		const gchar *ip, guint port)
-{
-	return g_object_new(PURPLE_MEDIA_TYPE_CANDIDATE,
-			"foundation", foundation,
-			"component-id", component_id,
-			"type", type,
-			"protocol", proto,
-			"ip", ip,
-			"port", port, NULL);
-}
-
-PurpleMediaCandidate *
-purple_media_candidate_copy(PurpleMediaCandidate *candidate)
-{
-	PurpleMediaCandidatePrivate *priv;
-	PurpleMediaCandidate *new_candidate;
-
-	if (candidate == NULL) {
-		return NULL;
-	}
-
-	priv = purple_media_candidate_get_instance_private(candidate);
-
-	new_candidate = purple_media_candidate_new(priv->foundation,
-			priv->component_id, priv->type, priv->proto,
-			priv->ip, priv->port);
-	g_object_set(new_candidate,
-			"base-ip", priv->base_ip,
-			"base-port", priv->base_port,
-			"priority", priv->priority,
-			"username", priv->username,
-			"password", priv->password,
-			"ttl", priv->ttl, NULL);
-	return new_candidate;
-}
-
-GList *
-purple_media_candidate_list_copy(GList *candidates)
-{
-	return g_list_copy_deep(candidates,
-	                        (GCopyFunc)(GCallback)purple_media_candidate_copy,
-	                        NULL);
-}
-
-void
-purple_media_candidate_list_free(GList *candidates)
-{
-	g_list_free_full(candidates, g_object_unref);
-}
-
-gchar *
-purple_media_candidate_get_foundation(PurpleMediaCandidate *candidate)
-{
-	gchar *foundation;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate), NULL);
-	g_object_get(candidate, "foundation", &foundation, NULL);
-	return foundation;
-}
-
-guint
-purple_media_candidate_get_component_id(PurpleMediaCandidate *candidate)
-{
-	guint component_id;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate), 0);
-	g_object_get(candidate, "component-id", &component_id, NULL);
-	return component_id;
-}
-
-gchar *
-purple_media_candidate_get_ip(PurpleMediaCandidate *candidate)
-{
-	gchar *ip;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate), NULL);
-	g_object_get(candidate, "ip", &ip, NULL);
-	return ip;
-}
-
-guint16
-purple_media_candidate_get_port(PurpleMediaCandidate *candidate)
-{
-	guint port;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate), 0);
-	g_object_get(candidate, "port", &port, NULL);
-	return port;
-}
-
-gchar *
-purple_media_candidate_get_base_ip(PurpleMediaCandidate *candidate)
-{
-	gchar *base_ip;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate), NULL);
-	g_object_get(candidate, "base-ip", &base_ip, NULL);
-	return base_ip;
-}
-
-guint16
-purple_media_candidate_get_base_port(PurpleMediaCandidate *candidate)
-{
-	guint base_port;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate), 0);
-	g_object_get(candidate, "base_port", &base_port, NULL);
-	return base_port;
-}
-
-PurpleMediaNetworkProtocol
-purple_media_candidate_get_protocol(PurpleMediaCandidate *candidate)
-{
-	PurpleMediaNetworkProtocol protocol;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate),
-			PURPLE_MEDIA_NETWORK_PROTOCOL_UDP);
-	g_object_get(candidate, "protocol", &protocol, NULL);
-	return protocol;
-}
-
-guint32
-purple_media_candidate_get_priority(PurpleMediaCandidate *candidate)
-{
-	guint priority;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate), 0);
-	g_object_get(candidate, "priority", &priority, NULL);
-	return priority;
-}
-
-PurpleMediaCandidateType
-purple_media_candidate_get_candidate_type(PurpleMediaCandidate *candidate)
-{
-	PurpleMediaCandidateType type;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate),
-			PURPLE_MEDIA_CANDIDATE_TYPE_HOST);
-	g_object_get(candidate, "type", &type, NULL);
-	return type;
-}
-
-gchar *
-purple_media_candidate_get_username(PurpleMediaCandidate *candidate)
-{
-	gchar *username;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate), NULL);
-	g_object_get(candidate, "username", &username, NULL);
-	return username;
-}
-
-gchar *
-purple_media_candidate_get_password(PurpleMediaCandidate *candidate)
-{
-	gchar *password;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate), NULL);
-	g_object_get(candidate, "password", &password, NULL);
-	return password;
-}
-
-guint
-purple_media_candidate_get_ttl(PurpleMediaCandidate *candidate)
-{
-	guint ttl;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CANDIDATE(candidate), 0);
-	g_object_get(candidate, "ttl", &ttl, NULL);
-	return ttl;
-}
-
diff --git a/libpurple/media/codec.h b/libpurple/media/codec.h
deleted file mode 100644
--- a/libpurple/media/codec.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_MEDIA_CODEC_H
-#define PURPLE_MEDIA_CODEC_H
-
-#include "enum-types.h"
-
-/**
- * PurpleMediaCodec:
- *
- * An opaque structure representing an audio or video codec.
- */
-typedef struct _PurpleMediaCodec PurpleMediaCodec;
-
-#include "purplekeyvaluepair.h"
-#include "purpleversion.h"
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-/**
- * PURPLE_MEDIA_TYPE_CODEC:
- *
- * The standard _get_type macro for #PurpleMediaCodec.
- *
- * Since: 3.0
- */
-#define PURPLE_MEDIA_TYPE_CODEC purple_media_codec_get_type()
-
-/**
- * purple_media_codec_get_type:
- *
- * Gets the type of the media codec structure.
- *
- * Returns: The media codec's GType
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-G_DECLARE_FINAL_TYPE(PurpleMediaCodec, purple_media_codec, PURPLE_MEDIA,
-                     CODEC, GObject)
-
-/**
- * purple_media_codec_new:
- * @id: Codec identifier.
- * @encoding_name: Name of the media type this encodes.
- * @media_type: PurpleMediaSessionType of this codec.
- * @clock_rate: The clock rate this codec encodes at, if applicable.
- *
- * Creates a new PurpleMediaCodec instance.
- *
- * Returns: The newly created PurpleMediaCodec.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMediaCodec *purple_media_codec_new(int id, const char *encoding_name,
-		PurpleMediaSessionType media_type, guint clock_rate);
-
-/**
- * purple_media_codec_get_id:
- * @codec: The codec to get the id from.
- *
- * Gets the codec id.
- *
- * Returns: The codec id.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-guint purple_media_codec_get_id(PurpleMediaCodec *codec);
-
-/**
- * purple_media_codec_get_encoding_name:
- * @codec: The codec to get the encoding name from.
- *
- * Gets the encoding name.
- *
- * Returns: The encoding name.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gchar *purple_media_codec_get_encoding_name(PurpleMediaCodec *codec);
-
-/**
- * purple_media_codec_get_clock_rate:
- * @codec: The codec to get the clock rate from.
- *
- * Gets the clock rate.
- *
- * Returns: The clock rate.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-guint purple_media_codec_get_clock_rate(PurpleMediaCodec *codec);
-
-/**
- * purple_media_codec_get_channels:
- * @codec: The codec to get the number of channels from.
- *
- * Gets the number of channels.
- *
- * Returns: The number of channels.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-guint purple_media_codec_get_channels(PurpleMediaCodec *codec);
-
-/**
- * purple_media_codec_get_optional_parameters:
- * @codec: The codec to get the optional parameters from.
- *
- * Gets a list of the optional parameters.
- *
- * Returns: (element-type PurpleKeyValuePair) (transfer none): The list of
- *          optional parameters.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GList *purple_media_codec_get_optional_parameters(PurpleMediaCodec *codec);
-
-/**
- * purple_media_codec_add_optional_parameter:
- * @codec: The codec to add the parameter to.
- * @name: The name of the parameter to add.
- * @value: The value of the parameter to add.
- *
- * Adds an optional parameter to the codec.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_codec_add_optional_parameter(PurpleMediaCodec *codec,
-		const gchar *name, const gchar *value);
-
-/**
- * purple_media_codec_remove_optional_parameter:
- * @codec: The codec to remove the parameter from.
- * @param: A pointer to the parameter to remove.
- *
- * Removes an optional parameter from the codec.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_codec_remove_optional_parameter(PurpleMediaCodec *codec,
-		PurpleKeyValuePair *param);
-
-/**
- * purple_media_codec_get_optional_parameter:
- * @codec: The codec to find the parameter in.
- * @name: The name of the parameter to search for.
- * @value: The value to search for or NULL.
- *
- * Gets an optional parameter based on the values given.
- *
- * Returns: (transfer none): The value found or NULL.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleKeyValuePair *purple_media_codec_get_optional_parameter(
-		PurpleMediaCodec *codec, const gchar *name,
-		const gchar *value);
-
-/**
- * purple_media_codec_copy:
- * @codec: The codec to copy.
- *
- * Copies a PurpleMediaCodec object.
- *
- * Returns: (transfer full): The copy of the codec.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-PurpleMediaCodec *purple_media_codec_copy(PurpleMediaCodec *codec);
-
-/**
- * purple_media_codec_list_copy:
- * @codecs: (element-type PurpleMediaCodec) (transfer none): The list of codecs
- *          to be copied.
- *
- * Copies a GList of PurpleMediaCodec and its contents.
- *
- * Returns: (element-type PurpleMediaCodec) (transfer full): The copy of the
- *          codec list.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GList *purple_media_codec_list_copy(GList *codecs);
-
-/**
- * purple_media_codec_list_free:
- * @codecs: (element-type PurpleMediaCodec) (transfer full): The list of codecs
- *          to be freed.
- *
- * Frees a GList of PurpleMediaCodec and its contents.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_codec_list_free(GList *codecs);
-
-/**
- * purple_media_codec_to_string:
- * @codec: The codec to create the string of.
- *
- * Creates a string representation of the codec.
- *
- * Returns: The new string representation.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gchar *purple_media_codec_to_string(PurpleMediaCodec *codec);
-
-G_END_DECLS
-
-#endif /* PURPLE_MEDIA_CODEC_H */
diff --git a/libpurple/media/codec.c b/libpurple/media/codec.c
deleted file mode 100644
--- a/libpurple/media/codec.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "codec.h"
-
-struct _PurpleMediaCodec
-{
-	GObject parent;
-};
-
-typedef struct
-{
-	gint id;
-	char *encoding_name;
-	PurpleMediaSessionType media_type;
-	guint clock_rate;
-	guint channels;
-	GList *optional_params;
-} PurpleMediaCodecPrivate;
-
-enum {
-	PROP_0,
-	PROP_ID,
-	PROP_ENCODING_NAME,
-	PROP_MEDIA_TYPE,
-	PROP_CLOCK_RATE,
-	PROP_CHANNELS,
-	PROP_OPTIONAL_PARAMS,
-	N_PROPERTIES,
-};
-
-static GParamSpec *properties[N_PROPERTIES] = {NULL, };
-
-G_DEFINE_FINAL_TYPE_WITH_PRIVATE(PurpleMediaCodec, purple_media_codec,
-                                 G_TYPE_OBJECT)
-
-static void
-purple_media_codec_init(PurpleMediaCodec *info)
-{
-	PurpleMediaCodecPrivate *priv =
-			purple_media_codec_get_instance_private(info);
-	priv->encoding_name = NULL;
-	priv->optional_params = NULL;
-}
-
-static void
-purple_media_codec_finalize(GObject *info)
-{
-	PurpleMediaCodecPrivate *priv =
-			purple_media_codec_get_instance_private(
-					PURPLE_MEDIA_CODEC(info));
-	g_free(priv->encoding_name);
-	g_list_free_full(priv->optional_params, (GDestroyNotify)purple_key_value_pair_free);
-
-	G_OBJECT_CLASS(purple_media_codec_parent_class)->finalize(info);
-}
-
-static void
-purple_media_codec_set_property (GObject *object, guint prop_id,
-		const GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaCodecPrivate *priv;
-	g_return_if_fail(PURPLE_MEDIA_IS_CODEC(object));
-
-	priv = purple_media_codec_get_instance_private(
-			PURPLE_MEDIA_CODEC(object));
-
-	switch (prop_id) {
-		case PROP_ID:
-			priv->id = g_value_get_uint(value);
-			break;
-		case PROP_ENCODING_NAME:
-			g_free(priv->encoding_name);
-			priv->encoding_name = g_value_dup_string(value);
-			break;
-		case PROP_MEDIA_TYPE:
-			priv->media_type = g_value_get_flags(value);
-			break;
-		case PROP_CLOCK_RATE:
-			priv->clock_rate = g_value_get_uint(value);
-			break;
-		case PROP_CHANNELS:
-			priv->channels = g_value_get_uint(value);
-			break;
-		case PROP_OPTIONAL_PARAMS:
-			priv->optional_params = g_value_get_pointer(value);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(
-					object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_codec_get_property (GObject *object, guint prop_id,
-		GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaCodecPrivate *priv;
-	g_return_if_fail(PURPLE_MEDIA_IS_CODEC(object));
-
-	priv = purple_media_codec_get_instance_private(
-			PURPLE_MEDIA_CODEC(object));
-
-	switch (prop_id) {
-		case PROP_ID:
-			g_value_set_uint(value, priv->id);
-			break;
-		case PROP_ENCODING_NAME:
-			g_value_set_string(value, priv->encoding_name);
-			break;
-		case PROP_MEDIA_TYPE:
-			g_value_set_flags(value, priv->media_type);
-			break;
-		case PROP_CLOCK_RATE:
-			g_value_set_uint(value, priv->clock_rate);
-			break;
-		case PROP_CHANNELS:
-			g_value_set_uint(value, priv->channels);
-			break;
-		case PROP_OPTIONAL_PARAMS:
-			g_value_set_pointer(value, priv->optional_params);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(
-					object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_codec_class_init(PurpleMediaCodecClass *klass)
-{
-	GObjectClass *gobject_class = (GObjectClass*)klass;
-
-	gobject_class->finalize = purple_media_codec_finalize;
-	gobject_class->set_property = purple_media_codec_set_property;
-	gobject_class->get_property = purple_media_codec_get_property;
-
-	/**
-	 * PurpleMediaCodec:id:
-	 *
-	 * The numeric identifier of the codec.
-	 */
-	properties[PROP_ID] = g_param_spec_uint("id",
-			"ID",
-			"The numeric identifier of the codec.",
-			0, G_MAXUINT, 0,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleMediaCodec:encoding-name:
-	 *
-	 * The name of the codec.
-	 */
-	properties[PROP_ENCODING_NAME] = g_param_spec_string("encoding-name",
-			"Encoding Name",
-			"The name of the codec.",
-			NULL,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleMediaCodec:media-type:
-	 *
-	 * Whether this is an audio, video, or application codec.
-	 */
-	properties[PROP_MEDIA_TYPE] = g_param_spec_flags("media-type",
-			"Media Type",
-			"Whether this is an audio, video or application codec.",
-			PURPLE_MEDIA_TYPE_SESSION_TYPE,
-			PURPLE_MEDIA_NONE,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleMediaCodec:clock-rate:
-	 *
-	 * The clock rate for the codec.
-	 */
-	properties[PROP_CLOCK_RATE] = g_param_spec_uint("clock-rate",
-			"Create Callback",
-			"The function called to create this element.",
-			0, G_MAXUINT, 0,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleMediaCodec:channels:
-	 *
-	 * The number of channels in the codec.
-	 */
-	properties[PROP_CHANNELS] = g_param_spec_uint("channels",
-			"Channels",
-			"The number of channels in this codec.",
-			0, G_MAXUINT, 0,
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleMediaCodec:optional-params:
-	 *
-	 * A list of optional parameters for the codec.
-	 */
-	properties[PROP_OPTIONAL_PARAMS] = g_param_spec_pointer("optional-params",
-			"Optional Params",
-			"A list of optional parameters for the codec.",
-			G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	g_object_class_install_properties(gobject_class, N_PROPERTIES, properties);
-}
-
-PurpleMediaCodec *
-purple_media_codec_new(int id, const char *encoding_name,
-		PurpleMediaSessionType media_type, guint clock_rate)
-{
-	PurpleMediaCodec *codec =
-			g_object_new(PURPLE_MEDIA_TYPE_CODEC,
-			"id", id,
-			"encoding_name", encoding_name,
-			"media_type", media_type,
-			"clock-rate", clock_rate, NULL);
-	return codec;
-}
-
-guint
-purple_media_codec_get_id(PurpleMediaCodec *codec)
-{
-	guint id;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CODEC(codec), 0);
-	g_object_get(codec, "id", &id, NULL);
-	return id;
-}
-
-gchar *
-purple_media_codec_get_encoding_name(PurpleMediaCodec *codec)
-{
-	gchar *name;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CODEC(codec), NULL);
-	g_object_get(codec, "encoding-name", &name, NULL);
-	return name;
-}
-
-guint
-purple_media_codec_get_clock_rate(PurpleMediaCodec *codec)
-{
-	guint clock_rate;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CODEC(codec), 0);
-	g_object_get(codec, "clock-rate", &clock_rate, NULL);
-	return clock_rate;
-}
-
-guint
-purple_media_codec_get_channels(PurpleMediaCodec *codec)
-{
-	guint channels;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CODEC(codec), 0);
-	g_object_get(codec, "channels", &channels, NULL);
-	return channels;
-}
-
-GList *
-purple_media_codec_get_optional_parameters(PurpleMediaCodec *codec)
-{
-	GList *optional_params;
-	g_return_val_if_fail(PURPLE_MEDIA_IS_CODEC(codec), NULL);
-	g_object_get(codec, "optional-params", &optional_params, NULL);
-	return optional_params;
-}
-
-void
-purple_media_codec_add_optional_parameter(PurpleMediaCodec *codec,
-		const gchar *name, const gchar *value)
-{
-	PurpleMediaCodecPrivate *priv;
-	PurpleKeyValuePair *new_param;
-
-	g_return_if_fail(codec != NULL);
-	g_return_if_fail(name != NULL && value != NULL);
-
-	priv = purple_media_codec_get_instance_private(codec);
-
-	new_param = purple_key_value_pair_new_full(name, g_strdup(value), g_free);
-	priv->optional_params = g_list_append(
-			priv->optional_params, new_param);
-
-	g_object_notify_by_pspec(G_OBJECT(codec), properties[PROP_OPTIONAL_PARAMS]);
-}
-
-void
-purple_media_codec_remove_optional_parameter(PurpleMediaCodec *codec,
-		PurpleKeyValuePair *param)
-{
-	PurpleMediaCodecPrivate *priv;
-
-	g_return_if_fail(codec != NULL && param != NULL);
-
-	priv = purple_media_codec_get_instance_private(codec);
-
-	priv->optional_params =
-			g_list_remove(priv->optional_params, param);
-	purple_key_value_pair_free(param);
-
-	g_object_notify_by_pspec(G_OBJECT(codec), properties[PROP_OPTIONAL_PARAMS]);
-}
-
-PurpleKeyValuePair *
-purple_media_codec_get_optional_parameter(PurpleMediaCodec *codec,
-		const gchar *name, const gchar *value)
-{
-	PurpleMediaCodecPrivate *priv;
-	GList *iter;
-
-	g_return_val_if_fail(codec != NULL, NULL);
-	g_return_val_if_fail(name != NULL, NULL);
-
-	priv = purple_media_codec_get_instance_private(codec);
-
-	for (iter = priv->optional_params; iter; iter = g_list_next(iter)) {
-		PurpleKeyValuePair *param = iter->data;
-		if (!g_ascii_strcasecmp(param->key, name) &&
-				(value == NULL ||
-				!g_ascii_strcasecmp(param->value, value)))
-		{
-			return param;
-		}
-	}
-
-	return NULL;
-}
-
-PurpleMediaCodec *
-purple_media_codec_copy(PurpleMediaCodec *codec)
-{
-	PurpleMediaCodecPrivate *priv;
-	PurpleMediaCodec *new_codec;
-	GList *iter;
-
-	if (codec == NULL) {
-		return NULL;
-	}
-
-	priv = purple_media_codec_get_instance_private(codec);
-
-	new_codec = purple_media_codec_new(priv->id, priv->encoding_name,
-			priv->media_type, priv->clock_rate);
-	g_object_set(codec, "channels", priv->channels, NULL);
-
-	for (iter = priv->optional_params; iter; iter = g_list_next(iter)) {
-		PurpleKeyValuePair *param =
-				(PurpleKeyValuePair*)iter->data;
-		purple_media_codec_add_optional_parameter(new_codec,
-				param->key, param->value);
-	}
-
-	return new_codec;
-}
-
-GList *
-purple_media_codec_list_copy(GList *codecs)
-{
-	return g_list_copy_deep(codecs,
-	                        (GCopyFunc)(GCallback)purple_media_codec_copy,
-	                        NULL);
-}
-
-void
-purple_media_codec_list_free(GList *codecs)
-{
-	g_list_free_full(codecs, g_object_unref);
-}
-
-gchar *
-purple_media_codec_to_string(PurpleMediaCodec *codec)
-{
-	PurpleMediaCodecPrivate *priv;
-	GString *string = NULL;
-	GList *item;
-	const gchar *media_type_str = NULL;
-
-	if (codec == NULL) {
-		return g_strdup("(NULL)");
-	}
-
-	priv = purple_media_codec_get_instance_private(codec);
-
-	string = g_string_new("");
-
-	if (priv->media_type & PURPLE_MEDIA_AUDIO) {
-		media_type_str = "audio";
-	} else if (priv->media_type & PURPLE_MEDIA_VIDEO) {
-		media_type_str = "video";
-	} else if (priv->media_type & PURPLE_MEDIA_APPLICATION) {
-		media_type_str = "application";
-	}
-
-	g_string_printf(string, "%d: %s %s clock:%d channels:%d", priv->id,
-			media_type_str, priv->encoding_name,
-			priv->clock_rate, priv->channels);
-
-	for (item = priv->optional_params; item; item = g_list_next (item)) {
-		PurpleKeyValuePair *param = item->data;
-		g_string_append_printf (string, " %s=%s",
-				param->key, (gchar *)param->value);
-	}
-
-	return g_string_free(string, FALSE);
-}
-
diff --git a/libpurple/media/enum-types.h b/libpurple/media/enum-types.h
deleted file mode 100644
--- a/libpurple/media/enum-types.h
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_MEDIA_ENUM_TYPES_H
-#define PURPLE_MEDIA_ENUM_TYPES_H
-
-#include <glib-object.h>
-
-#include "purpleversion.h"
-
-G_BEGIN_DECLS
-
-/**
- * PURPLE_MEDIA_TYPE_CANDIDATE_TYPE:
- *
- * The standard _get_type macro for #PurpleMediaCandidateType.
- *
- * Since: 3.0
- */
-#define PURPLE_MEDIA_TYPE_CANDIDATE_TYPE (purple_media_candidate_type_get_type())
-
-/**
- * PURPLE_MEDIA_TYPE_CAPS:
- *
- * The standard _get_type macro for #PurpleMediaCaps.
- *
- * Since: 2.7
- */
-#define PURPLE_MEDIA_TYPE_CAPS (purple_media_caps_get_type())
-
-/**
- * PURPLE_MEDIA_TYPE_INFO_TYPE:
- *
- * The standard _get_type macro for #PurpleMediaInfoType.
- *
- * Since: 2.6
- */
-#define PURPLE_MEDIA_TYPE_INFO_TYPE (purple_media_info_type_get_type())
-
-/**
- * PURPLE_MEDIA_TYPE_NETWORK_PROTOCOL:
- *
- * The standard _get_type macro for #PurpleMediaNetworkProtocol.
- *
- * Since: 3.0
- */
-#define PURPLE_MEDIA_TYPE_NETWORK_PROTOCOL (purple_media_network_protocol_get_type())
-
-/**
- * PURPLE_MEDIA_TYPE_SESSION_TYPE:
- *
- * The standard _get_type macro for #PurpleMediaSessionType.
- *
- * Since: 3.0
- */
-#define PURPLE_MEDIA_TYPE_SESSION_TYPE (purple_media_session_type_get_type())
-
-/**
- * PURPLE_MEDIA_TYPE_STATE:
- *
- * The standard _get_type macro for #PurpleMediaState.
- *
- * Since: 3.0
- */
-#define PURPLE_MEDIA_TYPE_STATE (purple_media_state_get_type())
-
-/**
- * PurpleMediaCandidateType:
- * @PURPLE_MEDIA_CANDIDATE_TYPE_HOST: A host candidate (local).
- * @PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX: A server reflexive candidate.
- * @PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX: A peer reflexive candidate.
- * @PURPLE_MEDIA_CANDIDATE_TYPE_RELAY: A relay candidate.
- * @PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST: A multicast address.
- *
- * Media candidate types
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_TYPE_IN_2_6
-typedef enum {
-	PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
-	PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX,
-	PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX,
-	PURPLE_MEDIA_CANDIDATE_TYPE_RELAY,
-	PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST
-} PurpleMediaCandidateType;
-
-/**
- * PurpleMediaCaps:
- * @PURPLE_MEDIA_CAPS_NONE: No capabilities.
- * @PURPLE_MEDIA_CAPS_AUDIO: Bi-directional audio.
- * @PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION: Single direction audio.
- * @PURPLE_MEDIA_CAPS_VIDEO: Bi-directional video.
- * @PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION: Single direction video.
- * @PURPLE_MEDIA_CAPS_AUDIO_VIDEO: Bi-directional audio and video.
- * @PURPLE_MEDIA_CAPS_MODIFY_SESSION: Modifiable session.
- * @PURPLE_MEDIA_CAPS_CHANGE_DIRECTION: Initiator and destination can be
- *                                      switched.
- *
- * Media caps
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_TYPE_IN_2_6
-typedef enum {
-	PURPLE_MEDIA_CAPS_NONE = 0,
-	PURPLE_MEDIA_CAPS_AUDIO = 1,
-	PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION = 1 << 1,
-	PURPLE_MEDIA_CAPS_VIDEO = 1 << 2,
-	PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION = 1 << 3,
-	PURPLE_MEDIA_CAPS_AUDIO_VIDEO = 1 << 4,
-	PURPLE_MEDIA_CAPS_MODIFY_SESSION = 1 << 5,
-	PURPLE_MEDIA_CAPS_CHANGE_DIRECTION = 1 << 6
-} PurpleMediaCaps;
-
-/**
- * PurpleMediaComponentType:
- * @PURPLE_MEDIA_COMPONENT_NONE: Use this when specifying a component is
- *                               innapropriate.
- * @PURPLE_MEDIA_COMPONENT_RTP: This component is for RTP data.
- * @PURPLE_MEDIA_COMPONENT_RTCP: This component is for RTCP control.
- *
- * Media component types
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_TYPE_IN_2_6
-typedef enum {
-	PURPLE_MEDIA_COMPONENT_NONE = 0,
-	PURPLE_MEDIA_COMPONENT_RTP = 1,
-	PURPLE_MEDIA_COMPONENT_RTCP = 2
-} PurpleMediaComponentType;
-
-/**
- * PurpleMediaInfoType:
- * @PURPLE_MEDIA_INFO_HANGUP: Terminate the media.
- * @PURPLE_MEDIA_INFO_ACCEPT: Create/join the media.
- * @PURPLE_MEDIA_INFO_REJECT: Terminate the media, possibly noting that it was
- *                            rejected.
- * @PURPLE_MEDIA_INFO_MUTE: Mute the media.
- * @PURPLE_MEDIA_INFO_UNMUTE: Unmute the media.
- * @PURPLE_MEDIA_INFO_PAUSE: Pause the media.
- * @PURPLE_MEDIA_INFO_UNPAUSE: Unpause the media.
- * @PURPLE_MEDIA_INFO_HOLD: Put the media on hold.
- * @PURPLE_MEDIA_INFO_UNHOLD: Remove the media from hold.
- *
- * Media info types
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_TYPE_IN_2_6
-typedef enum {
-	PURPLE_MEDIA_INFO_HANGUP = 0,
-	PURPLE_MEDIA_INFO_ACCEPT,
-	PURPLE_MEDIA_INFO_REJECT,
-	PURPLE_MEDIA_INFO_MUTE,
-	PURPLE_MEDIA_INFO_UNMUTE,
-	PURPLE_MEDIA_INFO_PAUSE,
-	PURPLE_MEDIA_INFO_UNPAUSE,
-	PURPLE_MEDIA_INFO_HOLD,
-	PURPLE_MEDIA_INFO_UNHOLD
-} PurpleMediaInfoType;
-
-/**
- * PurpleMediaNetworkProtocol:
- * @PURPLE_MEDIA_NETWORK_PROTOCOL_UDP: A UDP based protocol.
- * @PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_PASSIVE: A TCP based protocol, will
- *                                             listen for incoming connections.
- * @PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_ACTIVE: A TCP based protocol, will
- *                                            attempt to open an outbound
- *                                            connection.
- * @PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_SO: A TCP based protocol, will listen for
- *                                        incoming connections and attempt an
- *                                        outbound connection at the same time
- *                                        as the peer (Simultanuous-Open).
- *
- * Media network protocols
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_TYPE_IN_2_6
-typedef enum {
-	PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
-	PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_PASSIVE,
-	PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_ACTIVE,
-	PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_SO,
-} PurpleMediaNetworkProtocol;
-
-/**
- * PurpleMediaSessionType:
- * @PURPLE_MEDIA_NONE: Used for errors.
- * @PURPLE_MEDIA_RECV_AUDIO: The session has incoming audio.
- * @PURPLE_MEDIA_SEND_AUDIO: The session has outgoing audio.
- * @PURPLE_MEDIA_RECV_VIDEO: The session has incoming video.
- * @PURPLE_MEDIA_SEND_VIDEO: The session has outgoing video.
- * @PURPLE_MEDIA_RECV_APPLICATION: The session has incoming application
- *                                 specific data.
- * @PURPLE_MEDIA_SEND_APPLICATION: The session has outgoing application
- *                                 specific data.
- * @PURPLE_MEDIA_AUDIO: An alias for #PURPLE_MEDIA_RECV_AUDIO and
- *                      #PURPLE_MEDIA_SEND_AUDIO.
- * @PURPLE_MEDIA_VIDEO: An alias for #PURPLE_MEDIA_RECV_VIDEO and
- *                      #PURPLE_MEDIA_SEND_VIDEO.
- * @PURPLE_MEDIA_APPLICATION: An alias for #PURPLE_MEDIA_RECV_APPLICATION
- *                            and #PURPLE_MEDIA_SEND_APPLICATION.
- *
- * Media session types
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_TYPE_IN_2_6
-typedef enum {
-	PURPLE_MEDIA_NONE	= 0,
-	PURPLE_MEDIA_RECV_AUDIO = 1 << 0,
-	PURPLE_MEDIA_SEND_AUDIO = 1 << 1,
-	PURPLE_MEDIA_RECV_VIDEO = 1 << 2,
-	PURPLE_MEDIA_SEND_VIDEO = 1 << 3,
-	PURPLE_MEDIA_RECV_APPLICATION = 1 << 4,
-	PURPLE_MEDIA_SEND_APPLICATION = 1 << 5,
-	PURPLE_MEDIA_AUDIO = PURPLE_MEDIA_RECV_AUDIO | PURPLE_MEDIA_SEND_AUDIO,
-	PURPLE_MEDIA_VIDEO = PURPLE_MEDIA_RECV_VIDEO | PURPLE_MEDIA_SEND_VIDEO,
-	PURPLE_MEDIA_APPLICATION = PURPLE_MEDIA_RECV_APPLICATION |
-                                   PURPLE_MEDIA_SEND_APPLICATION
-} PurpleMediaSessionType;
-
-/**
- * PurpleMediaState:
- * @PURPLE_MEDIA_STATE_NEW: The media has not yet connected.
- * @PURPLE_MEDIA_STATE_CONNECTED: The media is connected.
- * @PURPLE_MEDIA_STATE_END: The media has previously connected but has since
- *                          disconnected.
- *
- * Media state-changed types
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_TYPE_IN_2_6
-typedef enum {
-	PURPLE_MEDIA_STATE_NEW = 0,
-	PURPLE_MEDIA_STATE_CONNECTED,
-	PURPLE_MEDIA_STATE_END
-} PurpleMediaState;
-
-/**
- * purple_media_candidate_type_get_type:
- *
- * Gets the media candidate type's GType
- *
- * Returns: The media candidate type's GType.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GType purple_media_candidate_type_get_type(void);
-
-/**
- * purple_media_caps_get_type:
- *
- * Gets the type of the media caps flags
- *
- * Returns: The media caps flags' GType
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-GType purple_media_caps_get_type(void);
-
-/**
- * purple_media_info_type_get_type:
- *
- * Gets the type of the info type enum
- *
- * Returns: The info type enum's GType
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GType purple_media_info_type_get_type(void);
-
-/**
- * purple_media_network_protocol_get_type:
- *
- * Gets the media network protocol's GType
- *
- * Returns: The media network protocol's GType.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GType purple_media_network_protocol_get_type(void);
-
-/**
- * purple_media_session_type_get_type:
- *
- * Gets the media session type's GType
- *
- * Returns: The media session type's GType.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GType purple_media_session_type_get_type(void);
-
-/**
- * purple_media_state_get_type:
- *
- * Gets the type of the state enum
- *
- * Returns: The state enum's GType
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GType purple_media_state_get_type(void);
-
-G_END_DECLS
-
-#endif /* PURPLE_MEDIA_ENUM_TYPES */
diff --git a/libpurple/media/enum-types.c b/libpurple/media/enum-types.c
deleted file mode 100644
--- a/libpurple/media/enum-types.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "enum-types.h"
-
-/*
- * PurpleMediaCandidateType
- */
-
-GType
-purple_media_candidate_type_get_type(void)
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GEnumValue values[] = {
-			{ PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
-					"PURPLE_MEDIA_CANDIDATE_TYPE_HOST",
-					"host" },
-			{ PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX,
-					"PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX",
-					"srflx" },
-			{ PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX,
-					"PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX",
-					"prflx" },
-			{ PURPLE_MEDIA_CANDIDATE_TYPE_RELAY,
-					"PURPLE_MEDIA_CANDIDATE_TYPE_RELAY",
-					"relay" },
-			{ PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST,
-					"PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST",
-					"multicast" },
-			{ 0, NULL, NULL }
-		};
-		type = g_enum_register_static("PurpleMediaCandidateType",
-				values);
-	}
-	return type;
-}
-
-/*
- * PurpleMediaCaps
- */
-
-GType
-purple_media_caps_get_type(void)
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GEnumValue values[] = {
-			{ PURPLE_MEDIA_CAPS_NONE,
-					"PURPLE_MEDIA_CAPS_NONE", "none" },
-			{ PURPLE_MEDIA_CAPS_AUDIO,
-					"PURPLE_MEDIA_CAPS_AUDIO", "audio" },
-			{ PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION,
-					"PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION",
-					"audio-single-direction" },
-			{ PURPLE_MEDIA_CAPS_VIDEO,
-					"PURPLE_MEDIA_CAPS_VIDEO", "video" },
-			{ PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION,
-					"PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION",
-					"video-single-direction" },
-			{ PURPLE_MEDIA_CAPS_AUDIO_VIDEO,
-					"PURPLE_MEDIA_CAPS_AUDIO_VIDEO",
-					"audio-video" },
-			{ PURPLE_MEDIA_CAPS_MODIFY_SESSION,
-					"PURPLE_MEDIA_CAPS_MODIFY_SESSION",
-					"modify-session" },
-			{ PURPLE_MEDIA_CAPS_CHANGE_DIRECTION,
-					"PURPLE_MEDIA_CAPS_CHANGE_DIRECTION",
-					"change-direction" },
-			{ 0, NULL, NULL }
-		};
-		type = g_enum_register_static("PurpleMediaCaps", values);
-	}
-	return type;
-}
-
-/*
- * PurpleMediaInfoType
- */
-
-GType
-purple_media_info_type_get_type(void)
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GEnumValue values[] = {
-			{ PURPLE_MEDIA_INFO_HANGUP,
-					"PURPLE_MEDIA_INFO_HANGUP", "hangup" },
-			{ PURPLE_MEDIA_INFO_ACCEPT,
-					"PURPLE_MEDIA_INFO_ACCEPT", "accept" },
-			{ PURPLE_MEDIA_INFO_REJECT,
-					"PURPLE_MEDIA_INFO_REJECT", "reject" },
-			{ PURPLE_MEDIA_INFO_MUTE,
-					"PURPLE_MEDIA_INFO_MUTE", "mute" },
-			{ PURPLE_MEDIA_INFO_UNMUTE,
-					"PURPLE_MEDIA_INFO_UNMUTE", "unmute" },
-			{ PURPLE_MEDIA_INFO_PAUSE,
-					"PURPLE_MEDIA_INFO_PAUSE", "pause" },
-			{ PURPLE_MEDIA_INFO_UNPAUSE,
-					"PURPLE_MEDIA_INFO_UNPAUSE", "unpause" },
-			{ PURPLE_MEDIA_INFO_HOLD,
-					"PURPLE_MEDIA_INFO_HOLD", "hold" },
-			{ PURPLE_MEDIA_INFO_UNHOLD,
-					"PURPLE_MEDIA_INFO_HOLD", "unhold" },
-			{ 0, NULL, NULL }
-		};
-		type = g_enum_register_static("PurpleMediaInfoType", values);
-	}
-	return type;
-}
-
-/*
- * PurpleMediaNetworkProtocol
- */
-
-GType
-purple_media_network_protocol_get_type(void)
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GEnumValue values[] = {
-			{ PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
-					"PURPLE_MEDIA_NETWORK_PROTOCOL_UDP",
-					"udp" },
-			{ PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_PASSIVE,
-					"PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_PASSIVE",
-					"tcp-passive" },
-			{ PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_ACTIVE,
-					"PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_ACTIVE",
-					"tcp-active" },
-			{ PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_SO,
-					"PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_SO",
-					"tcp-so" },
-			{ 0, NULL, NULL }
-		};
-		type = g_enum_register_static("PurpleMediaNetworkProtocol",
-				values);
-	}
-	return type;
-}
-
-/*
- * PurpleMediaSessionType
- */
-
-GType
-purple_media_session_type_get_type(void)
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GFlagsValue values[] = {
-			{ PURPLE_MEDIA_NONE,
-				"PURPLE_MEDIA_NONE", "none" },
-			{ PURPLE_MEDIA_RECV_AUDIO,
-				"PURPLE_MEDIA_RECV_AUDIO", "recv-audio" },
-			{ PURPLE_MEDIA_SEND_AUDIO,
-				"PURPLE_MEDIA_SEND_AUDIO", "send-audio" },
-			{ PURPLE_MEDIA_RECV_VIDEO,
-				"PURPLE_MEDIA_RECV_VIDEO", "recv-video" },
-			{ PURPLE_MEDIA_SEND_VIDEO,
-				"PURPLE_MEDIA_SEND_VIDEO", "send-video" },
-			{ PURPLE_MEDIA_RECV_APPLICATION,
-				"PURPLE_MEDIA_RECV_APPLICATION", "recv-application" },
-			{ PURPLE_MEDIA_SEND_APPLICATION,
-				"PURPLE_MEDIA_SEND_APPLICATION", "send-application" },
-			{ PURPLE_MEDIA_AUDIO,
-				"PURPLE_MEDIA_AUDIO", "audio" },
-			{ PURPLE_MEDIA_VIDEO,
-				"PURPLE_MEDIA_VIDEO", "video" },
-			{ PURPLE_MEDIA_APPLICATION,
-				"PURPLE_MEDIA_APPLICATION", "application" },
-			{ 0, NULL, NULL }
-		};
-		type = g_flags_register_static(
-				"PurpleMediaSessionType", values);
-	}
-	return type;
-}
-
-/*
- * PurpleMediaState
- */
-
-GType
-purple_media_state_get_type(void)
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GEnumValue values[] = {
-			{ PURPLE_MEDIA_STATE_NEW,
-				"PURPLE_MEDIA_STATE_NEW", "new" },
-			{ PURPLE_MEDIA_STATE_CONNECTED,
-				"PURPLE_MEDIA_STATE_CONNECTED", "connected" },
-			{ PURPLE_MEDIA_STATE_END,
-				"PURPLE_MEDIA_STATE_END", "end" },
-			{ 0, NULL, NULL }
-		};
-		type = g_enum_register_static("PurpleMediaState", values);
-	}
-	return type;
-}
-
diff --git a/libpurple/mediamanager.h b/libpurple/mediamanager.h
deleted file mode 100644
--- a/libpurple/mediamanager.h
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_MEDIA_MANAGER_H
-#define PURPLE_MEDIA_MANAGER_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-typedef struct _PurpleMediaManager PurpleMediaManager;
-
-#include "media.h"
-#include "purpleaccount.h"
-#include "purpleversion.h"
-
-#define PURPLE_TYPE_MEDIA_MANAGER purple_media_manager_get_type()
-
-/**
- * PurpleMediaManagerClass:
- *
- * The media manager class.
- *
- * Since: 2.6
- */
-
-/**
- * PurpleMediaAppDataCallbacks:
- * @readable: Called when the stream has received data and is readable.
- * @writable: Called when the stream has become writable or has stopped being
- * writable.
- *
- * A set of callbacks that can be installed on an Application data session with
- * purple_media_manager_set_application_data_callbacks()
- *
- * Once installed the @readable callback will get called as long as data is
- * available to read, so the data must be read completely.
- * The @writable callback will only be called when the writable state of the
- * stream changes. The @writable argument defines whether the stream has
- * become writable or stopped being writable.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_TYPE_IN_2_6
-typedef struct {
-	void      (*readable)    (PurpleMediaManager *manager, PurpleMedia *media,
-		const gchar *session_id, const gchar *participant, gpointer user_data);
-	void      (*writable)    (PurpleMediaManager *manager, PurpleMedia *media,
-		const gchar *session_id, const gchar *participant, gboolean writable,
-		gpointer user_data);
-} PurpleMediaAppDataCallbacks;
-
-G_BEGIN_DECLS
-
-/**************************************************************************/
-/* Media Manager API                                                      */
-/**************************************************************************/
-
-PURPLE_AVAILABLE_IN_2_6
-G_DECLARE_FINAL_TYPE(PurpleMediaManager, purple_media_manager, PURPLE,
-		MEDIA_MANAGER, GObject)
-
-/**
- * purple_media_manager_get:
- *
- * Gets the "global" media manager object. It's created if it doesn't already exist.
- *
- * Returns: (transfer none): The "global" instance of the media manager object.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMediaManager *purple_media_manager_get(void);
-
-/**
- * purple_media_manager_create_media:
- * @manager: The media manager to create the session under.
- * @account: The account to create the session on.
- * @conference_type: The conference type to feed into Farstream.
- * @remote_user: The remote user to initiate the session with.
- * @initiator: TRUE if the local user is the initiator of this media call, FALSE otherwise.
- *
- * Creates a media session.
- *
- * Returns: (transfer full): A newly created media session.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMedia *purple_media_manager_create_media(PurpleMediaManager *manager,
-						PurpleAccount *account,
-						const char *conference_type,
-						const char *remote_user,
-						gboolean initiator);
-
-/**
- * purple_media_manager_get_media:
- * @manager: The media manager to get all of the sessions from.
- *
- * Gets all of the media sessions.
- *
- * Returns: (transfer none) (element-type PurpleMedia): A list of all the media sessions.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GList *purple_media_manager_get_media(PurpleMediaManager *manager);
-
-/**
- * purple_media_manager_get_media_by_account:
- * @manager: The media manager to get the sessions from.
- * @account: The account the sessions are on.
- *
- * Gets all of the media sessions for a given account.
- *
- * Returns: (transfer container) (element-type PurpleMedia): A list of the media sessions on the given account.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GList *purple_media_manager_get_media_by_account(
-		PurpleMediaManager *manager, PurpleAccount *account);
-
-/**
- * purple_media_manager_remove_media:
- * @manager: The media manager to remove the media session from.
- * @media: The media session to remove.
- *
- * Removes a media session from the media manager.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void
-purple_media_manager_remove_media(PurpleMediaManager *manager,
-				  PurpleMedia *media);
-
-/**
- * purple_media_manager_create_private_media:
- * @manager: The media manager to create the session under.
- * @account: The account to create the session on.
- * @conference_type: The conference type to feed into Farstream.
- * @remote_user: The remote user to initiate the session with.
- * @initiator: TRUE if the local user is the initiator of this media call, FALSE otherwise.
- *
- * Creates a private media session.
- * A private media session is a media session which is private to the caller. It is
- * meant to be used by plugins to create a media session that the front-end does not
- * get notified about. It is useful especially for sessions with a type of
- * PURPLE_MEDIA_APPLICATION which the front-end wouldn't know how to handle.
- *
- * Returns: (transfer full): A newly created media session.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMedia *purple_media_manager_create_private_media(
-                                                PurpleMediaManager *manager,
-						PurpleAccount *account,
-						const char *conference_type,
-						const char *remote_user,
-						gboolean initiator);
-
-/**
- * purple_media_manager_get_private_media:
- * @manager: The media manager to get all of the sessions from.
- *
- * Gets all of the private media sessions.
- *
- * Returns: (transfer none) (element-type PurpleMedia): A list of all the private media sessions.
- *
- * Since: 2.11
- */
-PURPLE_AVAILABLE_IN_2_11
-GList *purple_media_manager_get_private_media(PurpleMediaManager *manager);
-
-/**
- * purple_media_manager_get_private_media_by_account:
- * @manager: The media manager to get the sessions from.
- * @account: The account the sessions are on.
- *
- * Gets all of the private media sessions for a given account.
- *
- * Returns: (transfer container) (element-type PurpleMedia): A list of the private media sessions on the given account.
- *
- * Since: 2.11
- */
-PURPLE_AVAILABLE_IN_2_11
-GList *purple_media_manager_get_private_media_by_account(
-		PurpleMediaManager *manager, PurpleAccount *account);
-
-/**
- * purple_media_manager_create_output_window:
- * @manager: Manager the output windows are registered with.
- * @media: Media session the output windows are registered for.
- * @session_id: The session the output windows are registered with.
- * @participant: The participant the output windows are registered with.
- *
- * Signals that output windows should be created for the chosen stream.
- *
- * This shouldn't be called outside of mediamanager.c and media.c
- *
- * Returns: TRUE if it succeeded, FALSE if it failed.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_manager_create_output_window(
-		PurpleMediaManager *manager, PurpleMedia *media,
-		const gchar *session_id, const gchar *participant);
-
-/**
- * purple_media_manager_set_output_window:
- * @manager: The manager to register the output window with.
- * @media: The media instance to find the stream in.
- * @session_id: The session the stream is associated with.
- * @participant: The participant the stream is associated with.
- *
- * Registers a video output window to be created for a given stream.
- *
- * Returns: A unique ID to the registered output window, 0 if it failed.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gulong purple_media_manager_set_output_window(PurpleMediaManager *manager,
-		PurpleMedia *media, const gchar *session_id,
-		const gchar *participant);
-
-/**
- * purple_media_manager_remove_output_window:
- * @manager: The manager the output window was registered with.
- * @output_window_id: The ID of the output window.
- *
- * Remove a previously registered output window.
- *
- * Returns: TRUE if it found the output window and was successful, else FALSE.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gboolean purple_media_manager_remove_output_window(
-		PurpleMediaManager *manager, gulong output_window_id);
-
-/**
- * purple_media_manager_remove_output_windows:
- * @manager: The manager the output windows were registered with.
- * @media: The media instance the output windows were registered for.
- * @session_id: The session the output windows were registered for.
- * @participant: The participant the output windows were registered for.
- *
- * Remove all output windows for a given conference/session/participant/stream.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_manager_remove_output_windows(
-		PurpleMediaManager *manager, PurpleMedia *media,
-		const gchar *session_id, const gchar *participant);
-
-/**
- * purple_media_manager_set_ui_caps:
- * @manager: The manager to set the caps on.
- * @caps: The caps to set.
- *
- * Sets which media caps the UI supports.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_manager_set_ui_caps(PurpleMediaManager *manager,
-		PurpleMediaCaps caps);
-
-/**
- * purple_media_manager_get_ui_caps:
- * @manager: The manager to get caps from.
- *
- * Gets which media caps the UI supports.
- *
- * Returns: caps The caps retrieved.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-PurpleMediaCaps purple_media_manager_get_ui_caps(PurpleMediaManager *manager);
-
-/**
- * purple_media_manager_set_backend_type:
- * @manager: The manager to set the caps on.
- * @backend_type: The media backend type to use.
- *
- * Sets which media backend type media objects will use.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-void purple_media_manager_set_backend_type(PurpleMediaManager *manager,
-		GType backend_type);
-
-/**
- * purple_media_manager_get_backend_type:
- * @manager: The manager to get the media backend type from.
- *
- * Gets which media backend type media objects will use.
- *
- * Returns: The type of media backend type media objects will use.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-GType purple_media_manager_get_backend_type(PurpleMediaManager *manager);
-
-/**
- * purple_media_manager_set_application_data_callbacks:
- * @manager: The manager to register the callbacks with.
- * @media: The media instance to register the callbacks with.
- * @session_id: The session to register the callbacks with.
- * @participant: The participant to register the callbacks with.
- * @callbacks: The callbacks to be set on the session.
- * @user_data: a user_data argument for the callbacks.
- * @notify: a destroy notify function.
- *
- * Set callbacks on a session to be called when the stream becomes writable
- * or readable for media sessions of type #PURPLE_MEDIA_APPLICATION
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_media_manager_set_application_data_callbacks(
-	PurpleMediaManager *manager, PurpleMedia *media, const gchar *session_id,
-	const gchar *participant, PurpleMediaAppDataCallbacks *callbacks,
-	gpointer user_data, GDestroyNotify notify);
-
-/**
- * purple_media_manager_send_application_data:
- * @manager: The manager to send data with.
- * @media: The media instance to which the session belongs.
- * @session_id: The session to send data to.
- * @participant: The participant to send data to.
- * @buffer: The buffer of data to send.
- * @size: The size of @buffer
- * @blocking: Whether to block until the data was send or not.
- *
- * Sends a buffer of data to a #PURPLE_MEDIA_APPLICATION session.
- * If @blocking is set, unless an error occurred, the function will not return
- * until the data has been flushed into the network.
- * If the stream is not writable, the data will be queued. It is the
- * responsibility of the user to stop sending data when the stream isn't
- * writable anymore. It is also the responsibility of the user to only start
- * sending data after the stream has been configured correctly (encryption
- * parameters for example).
- *
- * Returns: Number of bytes sent or -1 in case of error.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gint purple_media_manager_send_application_data (
-	PurpleMediaManager *manager, PurpleMedia *media, const gchar *session_id,
-	const gchar *participant, gpointer buffer, guint size, gboolean blocking);
-
-/**
- * purple_media_manager_receive_application_data:
- * @manager: The manager to receive data with.
- * @media: The media instance to which the session belongs.
- * @session_id: The session to receive data from.
- * @participant: The participant to receive data from.
- * @buffer: The buffer to receive data into.
- * @max_size: The max_size of @buffer
- * @blocking: Whether to block until the buffer is entirely filled or return
- * with currently available data.
- *
- * Receive a buffer of data from a #PURPLE_MEDIA_APPLICATION session.
- * If @blocking is set, unless an error occurred, the function will not return
- * until @max_size bytes are read.
- *
- * Returns: Number of bytes received or -1 in case of error.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gint purple_media_manager_receive_application_data (
-	PurpleMediaManager *manager, PurpleMedia *media, const gchar *session_id,
-	const gchar *participant, gpointer buffer, guint max_size,
-	gboolean blocking);
-
-/*}@*/
-
-G_END_DECLS
-
-#endif /* PURPLE_MEDIA_MANAGER_H */
diff --git a/libpurple/mediamanager.c b/libpurple/mediamanager.c
deleted file mode 100644
--- a/libpurple/mediamanager.c
+++ /dev/null
@@ -1,2472 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include <glib/gi18n-lib.h>
-
-#include "debug.h"
-#include "glibcompat.h"
-#include "media.h"
-#include "mediamanager.h"
-#include "prefs.h"
-#include "purpleaccount.h"
-#include "purplepath.h"
-#include "purpleprivate.h"
-
-#include "media-gst.h"
-
-#include <gst/app/app.h>
-
-typedef struct _PurpleMediaOutputWindow PurpleMediaOutputWindow;
-typedef struct _PurpleMediaElementInfoPrivate PurpleMediaElementInfoPrivate;
-
-struct _PurpleMediaOutputWindow
-{
-	gulong id;
-	PurpleMedia *media;
-	gchar *session_id;
-	gchar *participant;
-	GstElement *sink;
-};
-
-typedef struct
-{
-	GstElement *pipeline;
-	PurpleMediaCaps ui_caps;
-	GList *medias;
-	GList *private_medias;
-	GList *elements;
-	GList *output_windows;
-	gulong next_output_window_id;
-	GType backend_type;
-	GstCaps *video_caps;
-
-	PurpleMediaElementInfo *video_src;
-	PurpleMediaElementInfo *video_sink;
-	PurpleMediaElementInfo *audio_src;
-	PurpleMediaElementInfo *audio_sink;
-
-	GstDeviceMonitor *device_monitor;
-
-	/* Application data streams */
-	GList *appdata_info; /* holds PurpleMediaAppDataInfo */
-	GMutex appdata_mutex;
-	guint appdata_cb_token; /* last used read/write callback token */
-} PurpleMediaManagerPrivate;
-
-/**
- * PurpleMediaManager:
- *
- * The media manager's data.
- */
-struct _PurpleMediaManager
-{
-	GObject parent;
-
-	/*< private >*/
-	PurpleMediaManagerPrivate *priv;
-};
-
-typedef struct {
-	PurpleMedia *media;
-	GWeakRef media_ref;
-	gchar *session_id;
-	gchar *participant;
-	PurpleMediaAppDataCallbacks callbacks;
-	gpointer user_data;
-	GDestroyNotify notify;
-	GstAppSrc *appsrc;
-	GstAppSink *appsink;
-	gint num_samples;
-	GstSample *current_sample;
-	guint sample_offset;
-	gboolean writable;
-	gboolean connected;
-	guint writable_cb_token;
-	guint readable_cb_token;
-	guint writable_timer_id;
-	guint readable_timer_id;
-	GCond readable_cond;
-} PurpleMediaAppDataInfo;
-
-static void purple_media_manager_finalize (GObject *object);
-static void free_appdata_info_locked (PurpleMediaAppDataInfo *info);
-static void purple_media_manager_init_device_monitor(PurpleMediaManager *manager);
-static void purple_media_manager_register_static_elements(PurpleMediaManager *manager);
-
-
-enum {
-	SIG_INIT_MEDIA,
-	SIG_INIT_PRIVATE_MEDIA,
-	SIG_UI_CAPS_CHANGED,
-	SIG_ELEMENTS_CHANGED,
-	N_SIGNALS,
-};
-static guint signals[N_SIGNALS] = {0, };
-
-static PurpleMediaManager *default_manager = NULL;
-
-G_DEFINE_FINAL_TYPE_WITH_PRIVATE(PurpleMediaManager, purple_media_manager,
-                                 G_TYPE_OBJECT);
-
-static void
-purple_media_manager_class_init (PurpleMediaManagerClass *klass)
-{
-	GObjectClass *gobject_class = (GObjectClass*)klass;
-
-	gobject_class->finalize = purple_media_manager_finalize;
-
-	/**
-	 * PurpleMediaManager::init-media:
-	 * @manager: The instance.
-	 * @media: The media.
-	 * @account: The account.
-	 * @remote_user: The remote user.
-	 *
-	 * Emitted to initialize @media.
-	 *
-	 * Returns: %TRUE if @media was initialized.
-	 */
-	signals[SIG_INIT_MEDIA] = g_signal_new("init-media",
-		G_TYPE_FROM_CLASS (klass),
-		G_SIGNAL_RUN_LAST,
-		0, NULL, NULL, NULL,
-		G_TYPE_BOOLEAN, 3, PURPLE_TYPE_MEDIA,
-		G_TYPE_POINTER, G_TYPE_STRING);
-
-	/**
-	 * PurpleMediaManager::init-private-media:
-	 * @manager: The instance.
-	 * @media: The media.
-	 * @account: The account.
-	 * @remote_user: The remote user.
-	 *
-	 * Emitted to initialize @media but not tell the user interface about it.
-	 *
-	 * Returns: %TRUE if @media was initialized.
-	 */
-	signals[SIG_INIT_PRIVATE_MEDIA] = g_signal_new("init-private-media",
-			G_TYPE_FROM_CLASS (klass),
-			G_SIGNAL_RUN_LAST,
-			0, NULL, NULL, NULL,
-			G_TYPE_BOOLEAN, 3, PURPLE_TYPE_MEDIA,
-			G_TYPE_POINTER, G_TYPE_STRING);
-
-	/**
-	 * PurpleMediaManager::ui-caps-changed:
-	 * @manager: The instance.
-	 * @new_caps: The new capabilities.
-	 * @old_caps: The old capabilities.
-	 *
-	 * Emitted when the user interface capabilities have changed.
-	 */
-	signals[SIG_UI_CAPS_CHANGED] = g_signal_new("ui-caps-changed",
-		G_TYPE_FROM_CLASS (klass),
-		G_SIGNAL_RUN_LAST,
-		0, NULL, NULL, NULL,
-		G_TYPE_NONE, 2, PURPLE_MEDIA_TYPE_CAPS,
-		PURPLE_MEDIA_TYPE_CAPS);
-
-	/**
-	 * PurpleMediaManager::elements-changed:
-	 * @manager: The instance.
-	 *
-	 * Emitted when the elements have changed in @manager.
-	 */
-	signals[SIG_ELEMENTS_CHANGED] = g_signal_new("elements-changed",
-			G_TYPE_FROM_CLASS(klass),
-			G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-			0, NULL, NULL, NULL,
-			G_TYPE_NONE, 0);
-}
-
-static void
-purple_media_manager_init (PurpleMediaManager *media)
-{
-	GError *error = NULL;
-
-	media->priv = purple_media_manager_get_instance_private(media);
-	media->priv->medias = NULL;
-	media->priv->private_medias = NULL;
-	media->priv->next_output_window_id = 1;
-	media->priv->appdata_info = NULL;
-	g_mutex_init (&media->priv->appdata_mutex);
-	if (gst_init_check(NULL, NULL, &error)) {
-		purple_media_manager_register_static_elements(media);
-		purple_media_manager_init_device_monitor(media);
-	} else {
-		purple_debug_error("mediamanager",
-				"GStreamer failed to initialize: %s.",
-				error ? error->message : "");
-		g_clear_error(&error);
-	}
-
-	purple_prefs_add_none("/purple/media");
-	purple_prefs_add_none("/purple/media/audio");
-	purple_prefs_add_int("/purple/media/audio/silence_threshold", 5);
-	purple_prefs_add_none("/purple/media/audio/volume");
-	purple_prefs_add_int("/purple/media/audio/volume/input", 10);
-	purple_prefs_add_int("/purple/media/audio/volume/output", 10);
-}
-
-static void
-purple_media_manager_finalize(GObject *obj)
-{
-	PurpleMediaManager *manager = PURPLE_MEDIA_MANAGER(obj);
-	PurpleMediaManagerPrivate *priv = NULL;
-
-	priv = purple_media_manager_get_instance_private(manager);
-
-	if (priv->device_monitor) {
-		gst_device_monitor_stop(priv->device_monitor);
-		g_object_unref(priv->device_monitor);
-	}
-
-	g_clear_list(&priv->medias, g_object_unref);
-	g_clear_list(&priv->private_medias, g_object_unref);
-	g_clear_list(&priv->elements, g_object_unref);
-	g_clear_pointer(&priv->video_caps, gst_caps_unref);
-	g_clear_list(&priv->appdata_info,
-	             (GDestroyNotify)free_appdata_info_locked);
-	g_mutex_clear (&priv->appdata_mutex);
-
-	G_OBJECT_CLASS(purple_media_manager_parent_class)->finalize(obj);
-}
-
-PurpleMediaManager *
-purple_media_manager_get(void)
-{
-	if(!PURPLE_IS_MEDIA_MANAGER(default_manager)) {
-		default_manager = g_object_new(PURPLE_TYPE_MEDIA_MANAGER, NULL);
-		g_object_add_weak_pointer(G_OBJECT(default_manager),
-		                          (gpointer *)&default_manager);
-	}
-
-	return default_manager;
-}
-
-void
-purple_media_manager_shutdown(void) {
-	g_clear_object(&default_manager);
-}
-
-static gboolean
-pipeline_bus_call(G_GNUC_UNUSED GstBus *bus, GstMessage *msg,
-                  G_GNUC_UNUSED PurpleMediaManager *manager)
-{
-	switch(GST_MESSAGE_TYPE(msg)) {
-		case GST_MESSAGE_EOS:
-			purple_debug_info("mediamanager", "End of Stream");
-			break;
-		case GST_MESSAGE_ERROR: {
-			gchar *debug = NULL;
-			GError *err = NULL;
-
-			gst_message_parse_error(msg, &err, &debug);
-
-			purple_debug_error("mediamanager", "gst pipeline error: %s",
-			                   err->message);
-			g_error_free(err);
-
-			if (debug) {
-				purple_debug_error("mediamanager", "Debug details: %s", debug);
-				g_free(debug);
-			}
-			break;
-		}
-		default:
-			break;
-	}
-	return TRUE;
-}
-
-GstElement *
-purple_media_manager_get_pipeline(PurpleMediaManager *manager)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL);
-
-	if (manager->priv->pipeline == NULL) {
-		GstBus *bus;
-		manager->priv->pipeline = gst_pipeline_new(NULL);
-
-		bus = gst_pipeline_get_bus(
-				GST_PIPELINE(manager->priv->pipeline));
-		gst_bus_add_signal_watch(GST_BUS(bus));
-		g_signal_connect(G_OBJECT(bus), "message",
-				G_CALLBACK(pipeline_bus_call), manager);
-		gst_bus_set_sync_handler(bus, gst_bus_sync_signal_handler, NULL, NULL);
-		gst_object_unref(bus);
-
-		gst_element_set_state(manager->priv->pipeline,
-				GST_STATE_PLAYING);
-	}
-
-	return manager->priv->pipeline;
-}
-
-static PurpleMedia *
-create_media(PurpleMediaManager *manager,
-			  PurpleAccount *account,
-			  const char *conference_type,
-			  const char *remote_user,
-			  gboolean initiator,
-			  gboolean private)
-{
-	PurpleMedia *media;
-	guint signal_id;
-
-	media = g_object_new(
-		PURPLE_TYPE_MEDIA,
-		"manager", manager,
-		"account", account,
-		"conference-type", conference_type,
-		"initiator", initiator,
-		NULL);
-
-	signal_id = private ?
-			signals[SIG_INIT_PRIVATE_MEDIA] :
-			signals[SIG_INIT_MEDIA];
-
-	if (g_signal_has_handler_pending(manager, signal_id, 0, FALSE)) {
-		gboolean signal_ret;
-
-		g_signal_emit(manager, signal_id, 0, media, account, remote_user,
-				&signal_ret);
-		if (signal_ret == FALSE) {
-			g_object_unref(media);
-			return NULL;
-		}
-	}
-
-	if (private) {
-		manager->priv->private_medias = g_list_append(
-			manager->priv->private_medias, media);
-	} else {
-		manager->priv->medias = g_list_append(manager->priv->medias, media);
-	}
-
-	return media;
-}
-
-static GList *
-get_media(PurpleMediaManager *manager, gboolean private)
-{
-	if (private) {
-		return manager->priv->private_medias;
-	} else {
-		return manager->priv->medias;
-	}
-}
-
-static GList *
-get_media_by_account(PurpleMediaManager *manager,
-		PurpleAccount *account, gboolean private)
-{
-	GList *media = NULL;
-	GList *iter;
-	PurpleAccount *media_account;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL);
-
-	if (private) {
-		iter = manager->priv->private_medias;
-	} else {
-		iter = manager->priv->medias;
-	}
-	for (; iter; iter = g_list_next(iter)) {
-		media_account = purple_media_get_account(iter->data);
-		if (media_account == account) {
-			media = g_list_prepend(media, iter->data);
-		}
-		g_object_unref (media_account);
-	}
-
-	return media;
-}
-
-void
-purple_media_manager_remove_media(PurpleMediaManager *manager, PurpleMedia *media)
-{
-	GList *list;
-	GList **medias = NULL;
-
-	g_return_if_fail(manager != NULL);
-
-	if ((list = g_list_find(manager->priv->medias, media))) {
-		medias = &manager->priv->medias;
-	} else if ((list = g_list_find(manager->priv->private_medias, media))) {
-		medias = &manager->priv->private_medias;
-	}
-
-	if (list) {
-		*medias = g_list_delete_link(*medias, list);
-
-		g_mutex_lock (&manager->priv->appdata_mutex);
-		list = manager->priv->appdata_info;
-		while (list) {
-			PurpleMediaAppDataInfo *info = list->data;
-			GList *next = list->next;
-
-			if (info->media == media) {
-				manager->priv->appdata_info = g_list_delete_link (
-					manager->priv->appdata_info, list);
-				free_appdata_info_locked (info);
-			}
-
-			list = next;
-		}
-		g_mutex_unlock (&manager->priv->appdata_mutex);
-	}
-}
-
-PurpleMedia *
-purple_media_manager_create_media(PurpleMediaManager *manager,
-				  PurpleAccount *account,
-				  const char *conference_type,
-				  const char *remote_user,
-				  gboolean initiator)
-{
-	return create_media (manager, account, conference_type,
-						  remote_user, initiator, FALSE);
-}
-
-GList *
-purple_media_manager_get_media(PurpleMediaManager *manager)
-{
-	return get_media (manager, FALSE);
-}
-
-GList *
-purple_media_manager_get_media_by_account(PurpleMediaManager *manager,
-		PurpleAccount *account)
-{
-	return get_media_by_account (manager, account, FALSE);
-}
-
-PurpleMedia *
-purple_media_manager_create_private_media(PurpleMediaManager *manager,
-				  PurpleAccount *account,
-				  const char *conference_type,
-				  const char *remote_user,
-				  gboolean initiator)
-{
-	return create_media (manager, account, conference_type,
-		remote_user, initiator, TRUE);
-}
-
-GList *
-purple_media_manager_get_private_media(PurpleMediaManager *manager)
-{
-	return get_media (manager, TRUE);
-}
-
-GList *
-purple_media_manager_get_private_media_by_account(PurpleMediaManager *manager,
-		PurpleAccount *account)
-{
-	return get_media_by_account (manager, account, TRUE);
-}
-
-static void
-free_appdata_info_locked (PurpleMediaAppDataInfo *info)
-{
-	GstAppSrcCallbacks null_src_cb = {
-		.need_data = NULL,
-		.enough_data = NULL,
-		.seek_data = NULL,
-	};
-	GstAppSinkCallbacks null_sink_cb = {
-		.eos = NULL,
-		.new_preroll = NULL,
-		.new_sample = NULL,
-	};
-
-	if (info->notify) {
-		info->notify(info->user_data);
-	}
-
-	info->media = NULL;
-	if (info->appsrc) {
-		/* Will call appsrc_destroyed. */
-		gst_app_src_set_callbacks (info->appsrc, &null_src_cb,
-				NULL, NULL);
-	}
-	if (info->appsink) {
-		/* Will call appsink_destroyed. */
-		gst_app_sink_set_callbacks (info->appsink, &null_sink_cb,
-				NULL, NULL);
-	}
-
-	/* Make sure no other thread is using the structure */
-	g_free (info->session_id);
-	g_free (info->participant);
-
-	/* This lets the potential read or write callbacks waiting for appdata_mutex
-	 * know the info structure has been destroyed. */
-	info->readable_cb_token = 0;
-	info->writable_cb_token = 0;
-
-	g_clear_handle_id(&info->readable_timer_id, g_source_remove);
-	g_clear_handle_id(&info->writable_timer_id, g_source_remove);
-
-	g_clear_pointer(&info->current_sample, gst_sample_unref);
-
-	/* Unblock any reading thread before destroying the GCond */
-	g_cond_broadcast (&info->readable_cond);
-
-	g_cond_clear (&info->readable_cond);
-
-	g_slice_free (PurpleMediaAppDataInfo, info);
-}
-
-/*
- * Get an app data info struct associated with a session and lock the mutex
- * We don't want to return an info struct and unlock then it gets destroyed
- * so we need to return it with the lock still taken
- */
-static PurpleMediaAppDataInfo *
-get_app_data_info_and_lock (PurpleMediaManager *manager,
-	PurpleMedia *media, const gchar *session_id, const gchar *participant)
-{
-	GList *i;
-
-	g_mutex_lock (&manager->priv->appdata_mutex);
-	for (i = manager->priv->appdata_info; i; i = i->next) {
-		PurpleMediaAppDataInfo *info = i->data;
-
-		if (info->media == media &&
-			purple_strequal (info->session_id, session_id) &&
-			(participant == NULL ||
-				purple_strequal (info->participant, participant))) {
-			return info;
-		}
-	}
-
-	return NULL;
-}
-
-/*
- * Get an app data info struct associated with a session and lock the mutex
- * if it doesn't exist, we create it.
- */
-static PurpleMediaAppDataInfo *
-ensure_app_data_info_and_lock (PurpleMediaManager *manager, PurpleMedia *media,
-	const gchar *session_id, const gchar *participant)
-{
-	PurpleMediaAppDataInfo * info = get_app_data_info_and_lock (manager, media,
-		session_id, participant);
-
-	if (info == NULL) {
-		info = g_slice_new0 (PurpleMediaAppDataInfo);
-		info->media = media;
-		g_weak_ref_init (&info->media_ref, media);
-		info->session_id = g_strdup (session_id);
-		info->participant = g_strdup (participant);
-		g_cond_init (&info->readable_cond);
-		manager->priv->appdata_info = g_list_prepend (
-			manager->priv->appdata_info, info);
-	}
-
-	return info;
-}
-
-
-static void
-request_pad_unlinked_cb(GstPad *pad, G_GNUC_UNUSED GstPad *peer,
-                        G_GNUC_UNUSED gpointer user_data)
-{
-	GstElement *parent = GST_ELEMENT_PARENT(pad);
-	GstIterator *iter;
-	GValue tmp = G_VALUE_INIT;
-	GstIteratorResult result;
-
-	gst_element_release_request_pad(parent, pad);
-
-	iter = gst_element_iterate_src_pads(parent);
-
-	result = gst_iterator_next(iter, &tmp);
-
-	if (result == GST_ITERATOR_DONE) {
-		gst_element_set_locked_state(parent, TRUE);
-		gst_element_set_state(parent, GST_STATE_NULL);
-		gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(parent)), parent);
-	} else if (result == GST_ITERATOR_OK) {
-		g_value_reset(&tmp);
-	}
-
-	gst_iterator_free(iter);
-}
-
-static void
-nonunique_src_unlinked_cb(GstPad *pad, G_GNUC_UNUSED GstPad *peer,
-                          G_GNUC_UNUSED gpointer user_data)
-{
-	GstElement *element = GST_ELEMENT_PARENT(pad);
-	gst_element_set_locked_state(element, TRUE);
-	gst_element_set_state(element, GST_STATE_NULL);
-	gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(element)), element);
-}
-
-void
-purple_media_manager_set_video_caps(PurpleMediaManager *manager, GstCaps *caps)
-{
-	g_clear_pointer(&manager->priv->video_caps, gst_caps_unref);
-
-	manager->priv->video_caps = caps;
-
-	if (manager->priv->pipeline && manager->priv->video_src) {
-		gchar *id = purple_media_element_info_get_id(manager->priv->video_src);
-		GstElement *src = gst_bin_get_by_name(GST_BIN(manager->priv->pipeline), id);
-
-		if (src) {
-			GstElement *capsfilter = gst_bin_get_by_name(GST_BIN(src), "protocol_video_caps");
-			if (capsfilter) {
-				g_object_set(capsfilter, "caps", caps, NULL);
-				gst_object_unref (capsfilter);
-			}
-			gst_object_unref (src);
-		}
-
-		g_free(id);
-	}
-}
-
-GstCaps *
-purple_media_manager_get_video_caps(PurpleMediaManager *manager)
-{
-	if (manager->priv->video_caps == NULL) {
-		manager->priv->video_caps = gst_caps_from_string("video/x-raw,"
-			"width=[250,352], height=[200,288], framerate=[1/1,20/1]");
-	}
-
-	return manager->priv->video_caps;
-}
-
-/*
- * Calls the appdata writable callback from the main thread.
- * This needs to grab the appdata lock and make sure it didn't get destroyed
- * before calling the callback.
- */
-static gboolean
-appsrc_writable (gpointer user_data)
-{
-	PurpleMediaManager *manager = purple_media_manager_get ();
-	PurpleMediaAppDataInfo *info = user_data;
-	void (*writable_cb) (PurpleMediaManager *manager, PurpleMedia *media,
-		const gchar *session_id, const gchar *participant, gboolean writable,
-		gpointer user_data);
-	PurpleMedia *media;
-	gchar *session_id;
-	gchar *participant;
-	gboolean writable;
-	gpointer cb_data;
-	guint *cb_token_ptr = &info->writable_cb_token;
-	guint cb_token = *cb_token_ptr;
-
-
-	g_mutex_lock (&manager->priv->appdata_mutex);
-	if (cb_token == 0 || cb_token != *cb_token_ptr) {
-		/* In case info was freed while we were waiting for the mutex to unlock
-		 * we still have a pointer to the cb_token which should still be
-		 * accessible since it's in the Glib slice allocator. It gets set to 0
-		 * just after the timeout is canceled which happens also before the
-		 * AppDataInfo is freed, so even if that memory slice gets reused, the
-		 * cb_token would be different from its previous value (unless
-		 * extremely unlucky). So checking if the value for the cb_token changed
-		 * should be enough to prevent any kind of race condition in which the
-		 * media/AppDataInfo gets destroyed in one thread while the timeout was
-		 * triggered and is waiting on the mutex to get unlocked in this thread
-		 */
-		g_mutex_unlock (&manager->priv->appdata_mutex);
-		return FALSE;
-	}
-	writable_cb = info->callbacks.writable;
-	media = g_weak_ref_get (&info->media_ref);
-	session_id = g_strdup (info->session_id);
-	participant = g_strdup (info->participant);
-	writable = info->writable && info->connected;
-	cb_data = info->user_data;
-
-	info->writable_cb_token = 0;
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-
-
-	if (writable_cb && media) {
-		writable_cb (manager, media, session_id, participant, writable,
-			cb_data);
-	}
-
-	g_object_unref (media);
-	g_free (session_id);
-	g_free (participant);
-
-	return FALSE;
-}
-
-/*
- * Schedule a writable callback to be called from the main thread.
- * We need to do this because need-data/enough-data signals from appsrc
- * will come from the streaming thread and we need to create
- * a source that we attach to the main context but we can't use
- * g_main_context_invoke since we need to be able to cancel the source if the
- * media gets destroyed.
- * We use a timeout source instead of idle source, so the callback gets a higher
- * priority
- */
-static void
-call_appsrc_writable_locked (PurpleMediaAppDataInfo *info)
-{
-	PurpleMediaManager *manager = purple_media_manager_get ();
-
-	/* We already have a writable callback scheduled, don't create another one */
-	if (info->writable_cb_token || info->callbacks.writable == NULL) {
-		return;
-	}
-
-	/* We can't use writable_timer_id as a token, because the timeout is added
-	 * into libpurple's main event loop, which runs in a different thread than
-	 * from where call_appsrc_writable_locked() was called. Consequently, the
-	 * callback may run even before g_timeout_add() returns the timer ID
-	 * to us. */
-	info->writable_cb_token = ++manager->priv->appdata_cb_token;
-	info->writable_timer_id = g_timeout_add (0, appsrc_writable, info);
-}
-
-static void
-appsrc_need_data(G_GNUC_UNUSED GstAppSrc *appsrc, G_GNUC_UNUSED guint length,
-                 gpointer user_data)
-{
-	PurpleMediaAppDataInfo *info = user_data;
-	PurpleMediaManager *manager = purple_media_manager_get ();
-
-	g_mutex_lock (&manager->priv->appdata_mutex);
-	if (!info->writable) {
-		info->writable = TRUE;
-		/* Only signal writable if we also established a connection */
-		if (info->connected) {
-			call_appsrc_writable_locked (info);
-		}
-	}
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-}
-
-static void
-appsrc_enough_data(G_GNUC_UNUSED GstAppSrc *appsrc, gpointer user_data)
-{
-	PurpleMediaAppDataInfo *info = user_data;
-	PurpleMediaManager *manager = purple_media_manager_get ();
-
-	g_mutex_lock (&manager->priv->appdata_mutex);
-	if (info->writable) {
-		info->writable = FALSE;
-		call_appsrc_writable_locked (info);
-	}
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-}
-
-static gboolean
-appsrc_seek_data(G_GNUC_UNUSED GstAppSrc *appsrc, G_GNUC_UNUSED guint64 offset,
-                 G_GNUC_UNUSED gpointer user_data)
-{
-	return FALSE;
-}
-
-static void
-appsrc_destroyed (PurpleMediaAppDataInfo *info)
-{
-	PurpleMediaManager *manager;
-
-	if (!info->media) {
-		/* PurpleMediaAppDataInfo is being freed. Return at once. */
-		return;
-	}
-
-	manager = purple_media_manager_get ();
-
-	g_mutex_lock (&manager->priv->appdata_mutex);
-	info->appsrc = NULL;
-	if (info->writable) {
-		info->writable = FALSE;
-		call_appsrc_writable_locked (info);
-	}
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-}
-
-static void
-media_established_cb(G_GNUC_UNUSED PurpleMedia *media,
-                     G_GNUC_UNUSED const char *session_id,
-                     G_GNUC_UNUSED const char *participant,
-                     G_GNUC_UNUSED PurpleMediaCandidate *local_candidate,
-                     G_GNUC_UNUSED PurpleMediaCandidate *remote_candidate,
-                     PurpleMediaAppDataInfo *info)
-{
-	PurpleMediaManager *manager = purple_media_manager_get ();
-
-	g_mutex_lock (&manager->priv->appdata_mutex);
-	info->connected = TRUE;
-	/* We established the connection, if we were writable, then we need to
-	 * signal it now */
-	if (info->writable) {
-		call_appsrc_writable_locked (info);
-	}
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-}
-
-static GstElement *
-create_send_appsrc(G_GNUC_UNUSED PurpleMediaElementInfo *element_info,
-                   PurpleMedia *media, const char *session_id,
-                   const char *participant)
-{
-	PurpleMediaManager *manager = purple_media_manager_get ();
-	PurpleMediaAppDataInfo * info = ensure_app_data_info_and_lock (manager,
-		media, session_id, participant);
-	GstElement *appsrc = (GstElement *)info->appsrc;
-
-	if (appsrc == NULL) {
-		GstAppSrcCallbacks callbacks = {
-			.need_data = appsrc_need_data,
-			.enough_data = appsrc_enough_data,
-			.seek_data = appsrc_seek_data,
-		};
-		GstCaps *caps = gst_caps_new_empty_simple ("application/octet-stream");
-
-		appsrc = gst_element_factory_make("appsrc", NULL);
-
-		info->appsrc = (GstAppSrc *)appsrc;
-
-		gst_app_src_set_caps (info->appsrc, caps);
-		gst_app_src_set_callbacks (info->appsrc,
-			&callbacks, info, (GDestroyNotify) appsrc_destroyed);
-		g_signal_connect (media, "candidate-pair-established",
-			(GCallback) media_established_cb, info);
-		gst_caps_unref (caps);
-	}
-
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-	return appsrc;
-}
-
-static void
-appsink_eos(G_GNUC_UNUSED GstAppSink *appsink,
-            G_GNUC_UNUSED gpointer user_data)
-{
-}
-
-static GstFlowReturn
-appsink_new_preroll(G_GNUC_UNUSED GstAppSink *appsink,
-                    G_GNUC_UNUSED gpointer user_data)
-{
-	return GST_FLOW_OK;
-}
-
-static gboolean
-appsink_readable (gpointer user_data)
-{
-	PurpleMediaManager *manager = purple_media_manager_get ();
-	PurpleMediaAppDataInfo *info = user_data;
-	void (*readable_cb) (PurpleMediaManager *manager, PurpleMedia *media,
-		const gchar *session_id, const gchar *participant, gpointer user_data);
-	PurpleMedia *media;
-	gchar *session_id;
-	gchar *participant;
-	gpointer cb_data;
-	guint *cb_token_ptr = &info->readable_cb_token;
-	guint cb_token = *cb_token_ptr;
-	gboolean run_again = FALSE;
-
-	g_mutex_lock (&manager->priv->appdata_mutex);
-	if (cb_token == 0 || cb_token != *cb_token_ptr) {
-		/* Avoided a race condition (see writable callback) */
-		g_mutex_unlock (&manager->priv->appdata_mutex);
-		return FALSE;
-	}
-
-	if (info->callbacks.readable &&
-		(info->num_samples > 0 || info->current_sample != NULL)) {
-		readable_cb = info->callbacks.readable;
-		media = g_weak_ref_get (&info->media_ref);
-		session_id = g_strdup (info->session_id);
-		participant = g_strdup (info->participant);
-		cb_data = info->user_data;
-		g_mutex_unlock (&manager->priv->appdata_mutex);
-
-		readable_cb(manager, media, session_id, participant, cb_data);
-
-		g_mutex_lock (&manager->priv->appdata_mutex);
-		g_object_unref (media);
-		g_free (session_id);
-		g_free (participant);
-		if (cb_token != *cb_token_ptr) {
-			/* We got cancelled */
-			g_mutex_unlock (&manager->priv->appdata_mutex);
-			return FALSE;
-		}
-	}
-
-	/* Do we still have samples? Schedule appsink_readable again. We break here
-	 * so that other events get a chance to be processed too. */
-	if (info->num_samples > 0 || info->current_sample != NULL) {
-		run_again = TRUE;
-	} else {
-		info->readable_cb_token = 0;
-	}
-
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-	return run_again;
-}
-
-static void
-call_appsink_readable_locked (PurpleMediaAppDataInfo *info)
-{
-	PurpleMediaManager *manager = purple_media_manager_get ();
-
-	/* We must signal that a new sample has arrived to release blocking reads */
-	g_cond_broadcast (&info->readable_cond);
-
-	/* We already have a writable callback scheduled, don't create another one */
-	if (info->readable_cb_token || info->callbacks.readable == NULL) {
-		return;
-	}
-
-	info->readable_cb_token = ++manager->priv->appdata_cb_token;
-	info->readable_timer_id = g_timeout_add (0, appsink_readable, info);
-}
-
-static GstFlowReturn
-appsink_new_sample(G_GNUC_UNUSED GstAppSink *appsink, gpointer user_data)
-{
-	PurpleMediaManager *manager = purple_media_manager_get ();
-	PurpleMediaAppDataInfo *info = user_data;
-
-	g_mutex_lock (&manager->priv->appdata_mutex);
-	info->num_samples++;
-	call_appsink_readable_locked (info);
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-
-	return GST_FLOW_OK;
-}
-
-static void
-appsink_destroyed (PurpleMediaAppDataInfo *info)
-{
-	PurpleMediaManager *manager;
-
-	if (!info->media) {
-		/* PurpleMediaAppDataInfo is being freed. Return at once. */
-		return;
-	}
-
-	manager = purple_media_manager_get ();
-
-	g_mutex_lock (&manager->priv->appdata_mutex);
-	info->appsink = NULL;
-	info->num_samples = 0;
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-}
-
-static GstElement *
-create_recv_appsink(G_GNUC_UNUSED PurpleMediaElementInfo *element_info,
-                    PurpleMedia *media, const char *session_id,
-                    const char *participant)
-{
-	PurpleMediaManager *manager = purple_media_manager_get ();
-	PurpleMediaAppDataInfo * info = ensure_app_data_info_and_lock (manager,
-		media, session_id, participant);
-	GstElement *appsink = (GstElement *)info->appsink;
-
-	if (appsink == NULL) {
-		GstAppSinkCallbacks callbacks = {
-			.eos = appsink_eos,
-			.new_preroll = appsink_new_preroll,
-			.new_sample = appsink_new_sample,
-		};
-		GstCaps *caps = gst_caps_new_empty_simple ("application/octet-stream");
-
-		appsink = gst_element_factory_make("appsink", NULL);
-
-		info->appsink = (GstAppSink *)appsink;
-
-		gst_app_sink_set_caps (info->appsink, caps);
-		gst_app_sink_set_callbacks (info->appsink,
-			&callbacks, info, (GDestroyNotify) appsink_destroyed);
-		gst_caps_unref (caps);
-
-	}
-
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-	return appsink;
-}
-
-static PurpleMediaElementInfo *
-get_send_application_element_info(void)
-{
-	static PurpleMediaElementInfo *info = NULL;
-
-	if (info == NULL) {
-		info = g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
-			"id", "pidginappsrc",
-			"name", "Pidgin Application Source",
-			"type", PURPLE_MEDIA_ELEMENT_APPLICATION
-					| PURPLE_MEDIA_ELEMENT_SRC
-					| PURPLE_MEDIA_ELEMENT_ONE_SRC,
-			"create-cb", create_send_appsrc, NULL);
-	}
-
-	return info;
-}
-
-static PurpleMediaElementInfo *
-get_recv_application_element_info(void)
-{
-	static PurpleMediaElementInfo *info = NULL;
-
-	if (info == NULL) {
-		info = g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
-			"id", "pidginappsink",
-			"name", "Pidgin Application Sink",
-			"type", PURPLE_MEDIA_ELEMENT_APPLICATION
-					| PURPLE_MEDIA_ELEMENT_SINK
-					| PURPLE_MEDIA_ELEMENT_ONE_SINK,
-			"create-cb", create_recv_appsink, NULL);
-	}
-
-	return info;
-}
-
-GstElement *
-purple_media_manager_get_element(PurpleMediaManager *manager,
-		PurpleMediaSessionType type, PurpleMedia *media,
-		const gchar *session_id, const gchar *participant)
-{
-	GstElement *ret = NULL;
-	PurpleMediaElementInfo *info = NULL;
-	PurpleMediaElementType element_type;
-
-	if (type & PURPLE_MEDIA_SEND_AUDIO) {
-		info = manager->priv->audio_src;
-	} else if (type & PURPLE_MEDIA_RECV_AUDIO) {
-		info = manager->priv->audio_sink;
-	} else if (type & PURPLE_MEDIA_SEND_VIDEO) {
-		info = manager->priv->video_src;
-	} else if (type & PURPLE_MEDIA_RECV_VIDEO) {
-		info = manager->priv->video_sink;
-	} else if (type & PURPLE_MEDIA_SEND_APPLICATION) {
-		info = get_send_application_element_info ();
-	} else if (type & PURPLE_MEDIA_RECV_APPLICATION) {
-		info = get_recv_application_element_info ();
-	}
-
-	if (info == NULL) {
-		return NULL;
-	}
-
-	element_type = purple_media_element_info_get_element_type(info);
-
-	if (element_type & PURPLE_MEDIA_ELEMENT_UNIQUE &&
-			element_type & PURPLE_MEDIA_ELEMENT_SRC) {
-		GstElement *tee;
-		GstPad *pad;
-		GstPad *ghost;
-		gchar *id = purple_media_element_info_get_id(info);
-
-		ret = gst_bin_get_by_name(GST_BIN(
-				purple_media_manager_get_pipeline(
-				manager)), id);
-
-		if (ret == NULL) {
-			GstElement *bin, *fakesink;
-			ret = purple_media_element_info_call_create(info,
-					media, session_id, participant);
-			bin = gst_bin_new(id);
-			tee = gst_element_factory_make("tee", "tee");
-			gst_bin_add_many(GST_BIN(bin), ret, tee, NULL);
-
-			if (type & PURPLE_MEDIA_SEND_VIDEO) {
-				GstElement *videoscale;
-				GstElement *capsfilter;
-
-				videoscale = gst_element_factory_make("videoscale", NULL);
-				capsfilter = gst_element_factory_make("capsfilter", "protocol_video_caps");
-
-				g_object_set(capsfilter,
-					"caps", purple_media_manager_get_video_caps(manager), NULL);
-
-				gst_bin_add_many(GST_BIN(bin), videoscale, capsfilter, NULL);
-				gst_element_link_many(ret, videoscale, capsfilter, tee, NULL);
-			} else {
-				gst_element_link(ret, tee);
-			}
-
-			/*
-			 * This shouldn't be necessary, but it stops it from
-			 * giving a not-linked error upon destruction
-			 */
-			fakesink = gst_element_factory_make("fakesink", NULL);
-			g_object_set(fakesink,
-				"async", FALSE,
-				"sync", FALSE,
-				"enable-last-sample", FALSE,
-				NULL);
-			gst_bin_add(GST_BIN(bin), fakesink);
-			gst_element_link(tee, fakesink);
-
-			ret = bin;
-			gst_object_ref(ret);
-			gst_bin_add(GST_BIN(purple_media_manager_get_pipeline(
-					manager)), ret);
-		}
-		g_free(id);
-
-		tee = gst_bin_get_by_name(GST_BIN(ret), "tee");
-#if GST_CHECK_VERSION(1, 19, 1)
-		pad = gst_element_request_pad_simple(tee, "src_%u");
-#else
-		pad = gst_element_get_request_pad(tee, "src_%u");
-#endif
-		gst_object_unref(tee);
-		ghost = gst_ghost_pad_new(NULL, pad);
-		gst_object_unref(pad);
-		g_signal_connect(GST_PAD(ghost), "unlinked",
-				G_CALLBACK(request_pad_unlinked_cb), NULL);
-		gst_pad_set_active(ghost, TRUE);
-		gst_element_add_pad(ret, ghost);
-	} else {
-		ret = purple_media_element_info_call_create(info,
-				media, session_id, participant);
-		if (element_type & PURPLE_MEDIA_ELEMENT_SRC) {
-			GstPad *pad = gst_element_get_static_pad(ret, "src");
-			g_signal_connect(pad, "unlinked",
-					G_CALLBACK(nonunique_src_unlinked_cb), NULL);
-			gst_object_unref(pad);
-			gst_object_ref(ret);
-			gst_bin_add(GST_BIN(purple_media_manager_get_pipeline(manager)),
-				ret);
-		}
-	}
-
-	if (ret == NULL) {
-		purple_debug_error("media", "Error creating source or sink\n");
-	}
-
-	return ret;
-}
-
-PurpleMediaElementInfo *
-purple_media_manager_get_element_info(PurpleMediaManager *manager,
-		const gchar *id)
-{
-	GList *iter;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL);
-	g_return_val_if_fail(id != NULL, NULL);
-
-	iter = manager->priv->elements;
-
-	for (; iter; iter = g_list_next(iter)) {
-		gchar *element_id = purple_media_element_info_get_id(iter->data);
-		if (purple_strequal(element_id, id)) {
-			g_free(element_id);
-			g_object_ref(iter->data);
-			return iter->data;
-		}
-		g_free(element_id);
-	}
-
-	return NULL;
-}
-
-static GQuark
-element_info_to_detail(PurpleMediaElementInfo *info)
-{
-	PurpleMediaElementType type;
-
-	type = purple_media_element_info_get_element_type(info);
-
-	if (type & PURPLE_MEDIA_ELEMENT_AUDIO) {
-		if (type & PURPLE_MEDIA_ELEMENT_SRC) {
-			return g_quark_from_string("audiosrc");
-		} else if (type & PURPLE_MEDIA_ELEMENT_SINK) {
-			return g_quark_from_string("audiosink");
-		}
-	} else if (type & PURPLE_MEDIA_ELEMENT_VIDEO) {
-		if (type & PURPLE_MEDIA_ELEMENT_SRC) {
-			return g_quark_from_string("videosrc");
-		} else if (type & PURPLE_MEDIA_ELEMENT_SINK) {
-			return g_quark_from_string("videosink");
-		}
-	}
-
-	return 0;
-}
-
-gboolean
-purple_media_manager_register_element(PurpleMediaManager *manager,
-		PurpleMediaElementInfo *info)
-{
-	PurpleMediaElementInfo *info2;
-	gchar *id;
-	GQuark detail;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE);
-	g_return_val_if_fail(info != NULL, FALSE);
-
-	id = purple_media_element_info_get_id(info);
-	info2 = purple_media_manager_get_element_info(manager, id);
-	g_free(id);
-
-	if (info2 != NULL) {
-		g_object_unref(info2);
-		g_object_unref(info);
-		return FALSE;
-	}
-
-	manager->priv->elements = g_list_prepend(manager->priv->elements, info);
-
-	detail = element_info_to_detail(info);
-	if (detail != 0) {
-		g_signal_emit(manager, signals[SIG_ELEMENTS_CHANGED], detail);
-	}
-
-	return TRUE;
-}
-
-gboolean
-purple_media_manager_unregister_element(PurpleMediaManager *manager,
-		const gchar *id)
-{
-	PurpleMediaElementInfo *info;
-	GQuark detail;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE);
-
-	info = purple_media_manager_get_element_info(manager, id);
-
-	if (info == NULL) {
-		return FALSE;
-	}
-
-	if (manager->priv->audio_src == info) {
-		manager->priv->audio_src = NULL;
-	}
-	if (manager->priv->audio_sink == info) {
-		manager->priv->audio_sink = NULL;
-	}
-	if (manager->priv->video_src == info) {
-		manager->priv->video_src = NULL;
-	}
-	if (manager->priv->video_sink == info) {
-		manager->priv->video_sink = NULL;
-	}
-
-	detail = element_info_to_detail(info);
-
-	manager->priv->elements = g_list_remove(
-			manager->priv->elements, info);
-	g_object_unref(info);
-
-	if (detail != 0) {
-		g_signal_emit(manager, signals[SIG_ELEMENTS_CHANGED], detail);
-	}
-
-	return TRUE;
-}
-
-gboolean
-purple_media_manager_set_active_element(PurpleMediaManager *manager,
-		PurpleMediaElementInfo *info)
-{
-	PurpleMediaElementInfo *info2;
-	PurpleMediaElementType type;
-	gboolean ret = FALSE;
-	gchar *id;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE);
-	g_return_val_if_fail(info != NULL, FALSE);
-
-	id = purple_media_element_info_get_id(info);
-	info2 = purple_media_manager_get_element_info(manager, id);
-	g_free(id);
-
-	if (info2 == NULL) {
-		purple_media_manager_register_element(manager, g_object_ref(info));
-	} else {
-		g_object_unref(info2);
-	}
-
-	type = purple_media_element_info_get_element_type(info);
-
-	if (type & PURPLE_MEDIA_ELEMENT_SRC) {
-		if (type & PURPLE_MEDIA_ELEMENT_AUDIO) {
-			manager->priv->audio_src = info;
-			ret = TRUE;
-		}
-		if (type & PURPLE_MEDIA_ELEMENT_VIDEO) {
-			manager->priv->video_src = info;
-			ret = TRUE;
-		}
-	}
-	if (type & PURPLE_MEDIA_ELEMENT_SINK) {
-		if (type & PURPLE_MEDIA_ELEMENT_AUDIO) {
-			manager->priv->audio_sink = info;
-			ret = TRUE;
-		}
-		if (type & PURPLE_MEDIA_ELEMENT_VIDEO) {
-			manager->priv->video_sink = info;
-			ret = TRUE;
-		}
-	}
-
-	return ret;
-}
-
-PurpleMediaElementInfo *
-purple_media_manager_get_active_element(PurpleMediaManager *manager,
-		PurpleMediaElementType type)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL);
-
-	if (type & PURPLE_MEDIA_ELEMENT_SRC) {
-		if (type & PURPLE_MEDIA_ELEMENT_AUDIO) {
-			return manager->priv->audio_src;
-		} else if (type & PURPLE_MEDIA_ELEMENT_VIDEO) {
-			return manager->priv->video_src;
-		} else if (type & PURPLE_MEDIA_ELEMENT_APPLICATION) {
-			return get_send_application_element_info ();
-		}
-	} else if (type & PURPLE_MEDIA_ELEMENT_SINK) {
-		if (type & PURPLE_MEDIA_ELEMENT_AUDIO) {
-			return manager->priv->audio_sink;
-		} else if (type & PURPLE_MEDIA_ELEMENT_VIDEO) {
-			return manager->priv->video_sink;
-		} else if (type & PURPLE_MEDIA_ELEMENT_APPLICATION) {
-			return get_recv_application_element_info ();
-		}
-	}
-
-	return NULL;
-}
-
-gboolean
-purple_media_manager_create_output_window(PurpleMediaManager *manager,
-		PurpleMedia *media, const gchar *session_id,
-		const gchar *participant)
-{
-	GList *iter;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	iter = manager->priv->output_windows;
-	for(; iter; iter = g_list_next(iter)) {
-		PurpleMediaOutputWindow *ow = iter->data;
-
-		if (ow->sink == NULL && ow->media == media &&
-				purple_strequal(participant, ow->participant) &&
-				purple_strequal(session_id, ow->session_id)) {
-			GstElement *queue, *convert, *scale;
-			GstElement *tee = purple_media_get_tee(media,
-					session_id, participant);
-
-			if (tee == NULL) {
-				continue;
-			}
-
-			queue = gst_element_factory_make("queue", NULL);
-			convert = gst_element_factory_make("videoconvert", NULL);
-			scale = gst_element_factory_make("videoscale", NULL);
-			ow->sink = purple_media_manager_get_element(
-					manager, PURPLE_MEDIA_RECV_VIDEO,
-					ow->media, ow->session_id,
-					ow->participant);
-
-			if (participant == NULL) {
-				/* aka this is a preview sink */
-				GObjectClass *klass =
-						G_OBJECT_GET_CLASS(ow->sink);
-				if (g_object_class_find_property(klass, "sync")) {
-					g_object_set(ow->sink, "sync", FALSE, NULL);
-				}
-				if (g_object_class_find_property(klass, "async")) {
-					g_object_set(ow->sink, "async", FALSE, NULL);
-				}
-			}
-
-			gst_bin_add_many(GST_BIN(GST_ELEMENT_PARENT(tee)),
-					queue, convert, scale, ow->sink, NULL);
-
-			gst_element_set_state(ow->sink, GST_STATE_PLAYING);
-			gst_element_set_state(scale, GST_STATE_PLAYING);
-			gst_element_set_state(convert, GST_STATE_PLAYING);
-			gst_element_set_state(queue, GST_STATE_PLAYING);
-			gst_element_link(scale, ow->sink);
-			gst_element_link(convert, scale);
-			gst_element_link(queue, convert);
-			gst_element_link(tee, queue);
-		}
-	}
-	return TRUE;
-}
-
-gulong
-purple_media_manager_set_output_window(PurpleMediaManager *manager,
-		PurpleMedia *media, const gchar *session_id,
-		const gchar *participant)
-{
-	PurpleMediaOutputWindow *output_window;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE);
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	output_window = g_new0(PurpleMediaOutputWindow, 1);
-	output_window->id = manager->priv->next_output_window_id++;
-	output_window->media = media;
-	output_window->session_id = g_strdup(session_id);
-	output_window->participant = g_strdup(participant);
-
-	manager->priv->output_windows = g_list_prepend(
-			manager->priv->output_windows, output_window);
-
-	if (purple_media_get_tee(media, session_id, participant) != NULL) {
-		purple_media_manager_create_output_window(manager,
-				media, session_id, participant);
-	}
-
-	return output_window->id;
-}
-
-gboolean
-purple_media_manager_remove_output_window(PurpleMediaManager *manager,
-		gulong output_window_id)
-{
-	PurpleMediaOutputWindow *output_window = NULL;
-	GList *iter;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE);
-
-	iter = manager->priv->output_windows;
-	for (; iter; iter = g_list_next(iter)) {
-		PurpleMediaOutputWindow *ow = iter->data;
-		if (ow->id == output_window_id) {
-			manager->priv->output_windows = g_list_delete_link(
-					manager->priv->output_windows, iter);
-			output_window = ow;
-			break;
-		}
-	}
-
-	if (output_window == NULL) {
-		return FALSE;
-	}
-
-	if (output_window->sink != NULL) {
-		GstElement *element = output_window->sink;
-		GstPad *teepad = NULL;
-		GSList *to_remove = NULL;
-
-		/* Find the tee element this output is connected to. */
-		while (!teepad) {
-			GstPad *pad;
-			GstPad *peer;
-			GstElementFactory *factory;
-			const gchar *factory_name;
-
-			to_remove = g_slist_append(to_remove, element);
-
-			pad = gst_element_get_static_pad(element, "sink");
-			peer = gst_pad_get_peer(pad);
-			if (!peer) {
-				/* Output is disconnected from the pipeline. */
-				gst_object_unref(pad);
-				break;
-			}
-
-			factory = gst_element_get_factory(GST_PAD_PARENT(peer));
-			factory_name = gst_plugin_feature_get_name(factory);
-			if (purple_strequal(factory_name, "tee")) {
-				teepad = peer;
-			}
-
-			element = GST_PAD_PARENT(peer);
-
-			gst_object_unref(pad);
-			gst_object_unref(peer);
-		}
-
-		if (teepad) {
-			gst_element_release_request_pad(GST_PAD_PARENT(teepad),
-					teepad);
-		}
-
-		while (to_remove) {
-			GstElement *element = to_remove->data;
-
-			gst_element_set_locked_state(element, TRUE);
-			gst_element_set_state(element, GST_STATE_NULL);
-			gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(element)),
-					element);
-			to_remove = g_slist_delete_link(to_remove, to_remove);
-		}
-	}
-
-	g_free(output_window->session_id);
-	g_free(output_window->participant);
-	g_free(output_window);
-
-	return TRUE;
-}
-
-void
-purple_media_manager_remove_output_windows(PurpleMediaManager *manager,
-		PurpleMedia *media, const gchar *session_id,
-		const gchar *participant)
-{
-	GList *iter;
-
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-	iter = manager->priv->output_windows;
-
-	for (; iter;) {
-		PurpleMediaOutputWindow *ow = iter->data;
-		iter = g_list_next(iter);
-
-		if (media == ow->media &&
-				purple_strequal(session_id, ow->session_id) &&
-				purple_strequal(participant, ow->participant))
-		{
-			purple_media_manager_remove_output_window(
-					manager, ow->id);
-		}
-	}
-}
-
-void
-purple_media_manager_set_ui_caps(PurpleMediaManager *manager,
-		PurpleMediaCaps caps)
-{
-	PurpleMediaCaps oldcaps;
-
-	g_return_if_fail(PURPLE_IS_MEDIA_MANAGER(manager));
-
-	oldcaps = manager->priv->ui_caps;
-	manager->priv->ui_caps = caps;
-
-	if (caps != oldcaps) {
-		g_signal_emit(manager, signals[SIG_UI_CAPS_CHANGED], 0, caps, oldcaps);
-	}
-}
-
-PurpleMediaCaps
-purple_media_manager_get_ui_caps(PurpleMediaManager *manager)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager),
-			PURPLE_MEDIA_CAPS_NONE);
-	return manager->priv->ui_caps;
-}
-
-void
-purple_media_manager_set_backend_type(PurpleMediaManager *manager,
-		GType backend_type)
-{
-	g_return_if_fail(PURPLE_IS_MEDIA_MANAGER(manager));
-
-	manager->priv->backend_type = backend_type;
-}
-
-GType
-purple_media_manager_get_backend_type(PurpleMediaManager *manager)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager),
-			PURPLE_MEDIA_CAPS_NONE);
-
-	return manager->priv->backend_type;
-}
-
-void
-purple_media_manager_set_application_data_callbacks(PurpleMediaManager *manager,
-		PurpleMedia *media, const gchar *session_id,
-		const gchar *participant, PurpleMediaAppDataCallbacks *callbacks,
-		gpointer user_data, GDestroyNotify notify)
-{
-	PurpleMediaAppDataInfo * info = ensure_app_data_info_and_lock (manager,
-		media, session_id, participant);
-
-	if (info->notify) {
-		info->notify (info->user_data);
-	}
-
-	g_clear_handle_id(&info->readable_cb_token, g_source_remove);
-	g_clear_handle_id(&info->writable_cb_token, g_source_remove);
-
-	if (callbacks) {
-		info->callbacks = *callbacks;
-	} else {
-		info->callbacks.writable = NULL;
-		info->callbacks.readable = NULL;
-	}
-	info->user_data = user_data;
-	info->notify = notify;
-
-	call_appsrc_writable_locked (info);
-	if (info->num_samples > 0 || info->current_sample != NULL) {
-		call_appsink_readable_locked (info);
-	}
-
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-}
-
-gint
-purple_media_manager_send_application_data (
-	PurpleMediaManager *manager, PurpleMedia *media, const gchar *session_id,
-	const gchar *participant, gpointer buffer, guint size, gboolean blocking)
-{
-	PurpleMediaAppDataInfo * info = get_app_data_info_and_lock (manager,
-		media, session_id, participant);
-
-	if (info && info->appsrc && info->connected) {
-		GstBuffer *gstbuffer = gst_buffer_new_wrapped (g_memdup2(buffer, size),
-			size);
-		GstAppSrc *appsrc = gst_object_ref (info->appsrc);
-
-		g_mutex_unlock (&manager->priv->appdata_mutex);
-		if (gst_app_src_push_buffer (appsrc, gstbuffer) == GST_FLOW_OK) {
-			if (blocking) {
-				GstPad *srcpad;
-
-				srcpad = gst_element_get_static_pad (GST_ELEMENT (appsrc),
-					"src");
-				if (srcpad) {
-					gst_pad_peer_query (srcpad, gst_query_new_drain ());
-					gst_object_unref (srcpad);
-				}
-			}
-			gst_object_unref (appsrc);
-			return size;
-		} else {
-			gst_object_unref (appsrc);
-			return -1;
-		}
-	}
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-	return -1;
-}
-
-gint
-purple_media_manager_receive_application_data (
-	PurpleMediaManager *manager, PurpleMedia *media, const gchar *session_id,
-	const gchar *participant, gpointer buffer, guint max_size,
-	gboolean blocking)
-{
-	PurpleMediaAppDataInfo * info = get_app_data_info_and_lock (manager,
-		media, session_id, participant);
-	guint bytes_read = 0;
-
-	if (info) {
-		/* If we are in a blocking read, we need to loop until max_size data
-		 * is read into the buffer, if we're not, then we need to read as much
-		 * data as possible
-		 */
-		do {
-			if (!info->current_sample && info->appsink && info->num_samples > 0) {
-				info->current_sample = gst_app_sink_pull_sample (info->appsink);
-				info->sample_offset = 0;
-				if (info->current_sample) {
-					info->num_samples--;
-				}
-			}
-
-			if (info->current_sample) {
-				GstBuffer *gstbuffer = gst_sample_get_buffer (
-					info->current_sample);
-
-				if (gstbuffer) {
-					GstMapInfo mapinfo;
-					guint bytes_to_copy;
-
-					gst_buffer_map (gstbuffer, &mapinfo, GST_MAP_READ);
-					/* We must copy only the data remaining in the buffer without
-					 * overflowing the buffer */
-					bytes_to_copy = MIN(max_size - bytes_read,
-					                    mapinfo.size - info->sample_offset);
-					memcpy ((guint8 *)buffer + bytes_read,
-						mapinfo.data + info->sample_offset,	bytes_to_copy);
-
-					gst_buffer_unmap (gstbuffer, &mapinfo);
-					info->sample_offset += bytes_to_copy;
-					bytes_read += bytes_to_copy;
-					if (info->sample_offset == mapinfo.size) {
-						gst_sample_unref (info->current_sample);
-						info->current_sample = NULL;
-						info->sample_offset = 0;
-					}
-				} else {
-					/* In case there's no buffer in the sample (should never
-					 * happen), we need to at least unref it */
-					gst_sample_unref (info->current_sample);
-					info->current_sample = NULL;
-					info->sample_offset = 0;
-				}
-			}
-
-			/* If blocking, wait until there's an available sample */
-			while (bytes_read < max_size && blocking &&
-				info->current_sample == NULL && info->num_samples == 0) {
-				g_cond_wait (&info->readable_cond, &manager->priv->appdata_mutex);
-
-				/* We've been signaled, we need to unlock and regrab the info
-				 * struct to make sure nothing changed */
-				g_mutex_unlock (&manager->priv->appdata_mutex);
-				info = get_app_data_info_and_lock (manager,
-					media, session_id, participant);
-				if (info == NULL || info->appsink == NULL) {
-					/* The session was destroyed while we were waiting, we
-					 * should return here */
-					g_mutex_unlock (&manager->priv->appdata_mutex);
-					return bytes_read;
-				}
-			}
-		} while (bytes_read < max_size && (blocking || info->num_samples > 0));
-
-		g_mutex_unlock (&manager->priv->appdata_mutex);
-		return bytes_read;
-	}
-	g_mutex_unlock (&manager->priv->appdata_mutex);
-	return -1;
-}
-
-static void
-videosink_disable_last_sample(GstElement *sink)
-{
-	GObjectClass *klass = G_OBJECT_GET_CLASS(sink);
-
-	if (g_object_class_find_property(klass, "enable-last-sample")) {
-		g_object_set(sink, "enable-last-sample", FALSE, NULL);
-	}
-}
-
-static PurpleMediaElementType
-gst_class_to_purple_element_type(const gchar *device_class)
-{
-	if (purple_strequal(device_class, "Audio/Source")) {
-		return PURPLE_MEDIA_ELEMENT_AUDIO
-				| PURPLE_MEDIA_ELEMENT_SRC
-				| PURPLE_MEDIA_ELEMENT_ONE_SRC
-				| PURPLE_MEDIA_ELEMENT_UNIQUE;
-	} else if (purple_strequal(device_class, "Audio/Sink")) {
-		return PURPLE_MEDIA_ELEMENT_AUDIO
-				| PURPLE_MEDIA_ELEMENT_SINK
-				| PURPLE_MEDIA_ELEMENT_ONE_SINK;
-	} else if (purple_strequal(device_class, "Video/Source")) {
-		return PURPLE_MEDIA_ELEMENT_VIDEO
-				| PURPLE_MEDIA_ELEMENT_SRC
-				| PURPLE_MEDIA_ELEMENT_ONE_SRC
-				| PURPLE_MEDIA_ELEMENT_UNIQUE;
-	} else if (purple_strequal(device_class, "Video/Sink")) {
-		return PURPLE_MEDIA_ELEMENT_VIDEO
-				| PURPLE_MEDIA_ELEMENT_SINK
-				| PURPLE_MEDIA_ELEMENT_ONE_SINK;
-	}
-
-	return PURPLE_MEDIA_ELEMENT_NONE;
-}
-
-static GstElement *
-gst_device_create_cb(PurpleMediaElementInfo *info,
-                     G_GNUC_UNUSED PurpleMedia *media,
-                     G_GNUC_UNUSED const char *session_id,
-                     G_GNUC_UNUSED const char *participant)
-{
-	GstDevice *device;
-	GstElement *result;
-	PurpleMediaElementType type;
-
-	device = g_object_get_data(G_OBJECT(info), "gst-device");
-	if (!device) {
-		return NULL;
-	}
-
-	result = gst_device_create_element(device, NULL);
-	if (!result) {
-		return NULL;
-	}
-
-	type = purple_media_element_info_get_element_type(info);
-
-	if ((type & PURPLE_MEDIA_ELEMENT_VIDEO) &&
-	    (type & PURPLE_MEDIA_ELEMENT_SINK)) {
-		videosink_disable_last_sample(result);
-	}
-
-	return result;
-}
-
-static gboolean
-device_is_ignored(GstDevice *device)
-{
-	gboolean result = FALSE;
-
-	gchar *device_class;
-
-	g_return_val_if_fail(device, TRUE);
-
-	device_class = gst_device_get_device_class(device);
-
-	/* Ignore PulseAudio monitor audio sources since they have little use
-	 * in the context of telephony.*/
-	if (purple_strequal(device_class, "Audio/Source")) {
-		GstStructure *properties;
-		const gchar *pa_class;
-
-		properties = gst_device_get_properties(device);
-
-		pa_class = gst_structure_get_string(properties, "device.class");
-		if (purple_strequal(pa_class, "monitor")) {
-			result = TRUE;
-		}
-
-		gst_structure_free(properties);
-	}
-
-	g_free(device_class);
-
-	return result;
-}
-
-static void
-purple_media_manager_register_gst_device(PurpleMediaManager *manager,
-		GstDevice *device)
-{
-	PurpleMediaElementInfo *info;
-	PurpleMediaElementType type;
-	gchar *name;
-	gchar *device_class;
-	gchar *id;
-
-	if (device_is_ignored(device)) {
-		return;
-	}
-
-	name = gst_device_get_display_name(device);
-	device_class = gst_device_get_device_class(device);
-
-	id = g_strdup_printf("%s %s", device_class, name);
-
-	type = gst_class_to_purple_element_type(device_class);
-
-	info = g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
-			"id", id,
-			"name", name,
-			"type", type,
-			"create-cb", gst_device_create_cb,
-			NULL);
-
-	g_object_set_data(G_OBJECT(info), "gst-device", device);
-
-	purple_media_manager_register_element(manager, info);
-
-	purple_debug_info("mediamanager", "Registered %s device %s",
-			device_class, name);
-
-	g_free(name);
-	g_free(device_class);
-	g_free(id);
-}
-
-static void
-purple_media_manager_unregister_gst_device(PurpleMediaManager *manager,
-		GstDevice *device)
-{
-	GList *i;
-	gchar *name;
-	gchar *device_class;
-	gboolean done = FALSE;
-
-	name = gst_device_get_display_name(device);
-	device_class = gst_device_get_device_class(device);
-
-	for (i = manager->priv->elements; i && !done; i = i->next) {
-		PurpleMediaElementInfo *info = i->data;
-		GstDevice *device2;
-
-		device2 = g_object_get_data(G_OBJECT(info), "gst-device");
-		if (device2) {
-			gchar *name2;
-			gchar *device_class2;
-
-			name2 = gst_device_get_display_name(device2);
-			device_class2 = gst_device_get_device_class(device2);
-
-			if (purple_strequal(name, name2) &&
-			    purple_strequal(device_class, device_class2)) {
-				gchar *id;
-
-				id = purple_media_element_info_get_id(info);
-				purple_media_manager_unregister_element(manager,
-						id);
-
-				purple_debug_info("mediamanager",
-						"Unregistered %s device %s",
-						device_class, name);
-
-				g_free(id);
-
-				done = TRUE;
-			}
-
-			g_free(name2);
-			g_free(device_class2);
-		}
-	}
-
-	g_free(name);
-	g_free(device_class);
-}
-
-static gboolean
-device_monitor_bus_cb(G_GNUC_UNUSED GstBus *bus, GstMessage *message,
-                      gpointer user_data)
-{
-	PurpleMediaManager *manager = user_data;
-	GstMessageType message_type;
-	GstDevice *device;
-
-	message_type = GST_MESSAGE_TYPE(message);
-
-	if (message_type == GST_MESSAGE_DEVICE_ADDED) {
-		gst_message_parse_device_added(message, &device);
-		purple_media_manager_register_gst_device(manager, device);
-	} else if (message_type == GST_MESSAGE_DEVICE_REMOVED) {
-		gst_message_parse_device_removed (message, &device);
-		purple_media_manager_unregister_gst_device(manager, device);
-	}
-
-	return G_SOURCE_CONTINUE;
-}
-
-static void
-purple_media_manager_init_device_monitor(PurpleMediaManager *manager)
-{
-	GstBus *bus;
-	GList *i;
-
-	manager->priv->device_monitor = gst_device_monitor_new();
-
-	bus = gst_device_monitor_get_bus(manager->priv->device_monitor);
-	gst_bus_add_watch (bus, device_monitor_bus_cb, manager);
-	gst_object_unref (bus);
-
-	/* This avoids warning in GStreamer logs about no filters set */
-	gst_device_monitor_add_filter(manager->priv->device_monitor, NULL, NULL);
-
-	gst_device_monitor_start(manager->priv->device_monitor);
-
-	i = gst_device_monitor_get_devices(manager->priv->device_monitor);
-	for (; i; i = g_list_delete_link(i, i)) {
-		GstDevice *device = i->data;
-
-		purple_media_manager_register_gst_device(manager, device);
-		gst_object_unref(device);
-	}
-}
-
-GList *
-purple_media_manager_enumerate_elements(PurpleMediaManager *manager,
-		PurpleMediaElementType type)
-{
-	GList *result = NULL;
-	GList *i;
-
-	for (i = manager->priv->elements; i; i = i->next) {
-		PurpleMediaElementInfo *info = i->data;
-		PurpleMediaElementType type2;
-
-		type2 = purple_media_element_info_get_element_type(info);
-
-		if ((type2 & type) == type) {
-			g_object_ref(info);
-			result = g_list_prepend(result, info);
-		}
-	}
-
-	return result;
-}
-
-static GstElement *
-gst_factory_make_cb(PurpleMediaElementInfo *info,
-                    G_GNUC_UNUSED PurpleMedia *media,
-                    G_GNUC_UNUSED const char *session_id,
-                    G_GNUC_UNUSED const char *participant)
-{
-	gchar *id;
-	GstElement *element;
-
-	id = purple_media_element_info_get_id(info);
-
-	element = gst_element_factory_make(id, NULL);
-
-	g_free(id);
-
-	return element;
-}
-
-static void
-autovideosink_child_added_cb(G_GNUC_UNUSED GstChildProxy *child_proxy,
-                             GObject *object, G_GNUC_UNUSED gchar *name,
-                             G_GNUC_UNUSED gpointer user_data)
-{
-	videosink_disable_last_sample(GST_ELEMENT(object));
-}
-
-static GstElement *
-default_video_sink_create_cb(G_GNUC_UNUSED PurpleMediaElementInfo *info,
-                             G_GNUC_UNUSED PurpleMedia *media,
-                             G_GNUC_UNUSED const char *session_id,
-                             G_GNUC_UNUSED const char *participant)
-{
-	GstElement *videosink = gst_element_factory_make("autovideosink", NULL);
-
-	g_signal_connect(videosink, "child-added",
-			G_CALLBACK(autovideosink_child_added_cb), NULL);
-
-	return videosink;
-}
-
-static GstElement *
-disabled_video_create_cb(G_GNUC_UNUSED PurpleMediaElementInfo *info,
-                         G_GNUC_UNUSED PurpleMedia *media,
-                         G_GNUC_UNUSED const char *session_id,
-                         G_GNUC_UNUSED const char *participant)
-{
-	GstElement *src = gst_element_factory_make("videotestsrc", NULL);
-
-	/* GST_VIDEO_TEST_SRC_BLACK */
-	g_object_set(src, "pattern", 2, NULL);
-
-	return src;
-}
-
-static GstElement *
-test_video_create_cb(G_GNUC_UNUSED PurpleMediaElementInfo *info,
-                     G_GNUC_UNUSED PurpleMedia *media,
-                     G_GNUC_UNUSED const char *session_id,
-                     G_GNUC_UNUSED const char *participant)
-{
-	GstElement *src = gst_element_factory_make("videotestsrc", NULL);
-
-	g_object_set(src, "is-live", TRUE, NULL);
-
-	return src;
-}
-
-static void
-purple_media_manager_register_static_elements(PurpleMediaManager *manager)
-{
-	static const gchar *VIDEO_SINK_PLUGINS[] = {
-		"gtksink", "GTK",
-		"gtkglsink", "GTK OpenGL",
-		/* "aasink", "AALib", Didn't work for me */
-		NULL
-	};
-	const gchar **sinks = NULL;
-
-	/* Default auto* elements. */
-
-	purple_media_manager_register_element(manager,
-		g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
-			"id", "autoaudiosrc",
-			"name", N_("Default"),
-			"type", PURPLE_MEDIA_ELEMENT_AUDIO
-				| PURPLE_MEDIA_ELEMENT_SRC
-				| PURPLE_MEDIA_ELEMENT_ONE_SRC
-				| PURPLE_MEDIA_ELEMENT_UNIQUE,
-			"create-cb", gst_factory_make_cb,
-			NULL));
-
-	purple_media_manager_register_element(manager,
-		g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
-			"id", "autoaudiosink",
-			"name", N_("Default"),
-			"type", PURPLE_MEDIA_ELEMENT_AUDIO
-					| PURPLE_MEDIA_ELEMENT_SINK
-					| PURPLE_MEDIA_ELEMENT_ONE_SINK,
-			"create-cb", gst_factory_make_cb,
-			NULL));
-
-	purple_media_manager_register_element(manager,
-		g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
-			"id", "autovideosrc",
-			"name", N_("Default"),
-			"type", PURPLE_MEDIA_ELEMENT_VIDEO
-				| PURPLE_MEDIA_ELEMENT_SRC
-				| PURPLE_MEDIA_ELEMENT_ONE_SRC
-				| PURPLE_MEDIA_ELEMENT_UNIQUE,
-			"create-cb", gst_factory_make_cb,
-			NULL));
-
-	purple_media_manager_register_element(manager,
-		g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
-			"id", "autovideosink",
-			"name", N_("Default"),
-			"type", PURPLE_MEDIA_ELEMENT_VIDEO
-				| PURPLE_MEDIA_ELEMENT_SINK
-				| PURPLE_MEDIA_ELEMENT_ONE_SINK,
-			"create-cb", default_video_sink_create_cb,
-			NULL));
-
-	/* Special elements */
-
-	purple_media_manager_register_element(manager,
-		g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
-			"id", "audiotestsrc",
-			/* Translators: This is a noun that refers to one
-			 * possible audio input device. The device can help the
-			 * user to check if her speakers or headphones have been
-			 * set up correctly for voice calling. */
-			"name", N_("Test Sound"),
-			"type", PURPLE_MEDIA_ELEMENT_AUDIO
-				| PURPLE_MEDIA_ELEMENT_SRC
-				| PURPLE_MEDIA_ELEMENT_ONE_SRC,
-			"create-cb", gst_factory_make_cb,
-			NULL));
-
-	purple_media_manager_register_element(manager,
-		g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
-			"id", "disabledvideosrc",
-			"name", N_("Disabled"),
-			"type", PURPLE_MEDIA_ELEMENT_VIDEO
-				| PURPLE_MEDIA_ELEMENT_SRC
-				| PURPLE_MEDIA_ELEMENT_ONE_SINK,
-			"create-cb", disabled_video_create_cb,
-			NULL));
-
-	purple_media_manager_register_element(manager,
-		g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
-			"id", "videotestsrc",
-			/* Translators: This is a noun that refers to one
-			 * possible video input device. The device produces
-			 * a test "monoscope" image that can help the user check
-			 * the video output has been set up correctly without
-			 * needing a webcam connected to the computer. */
-			"name", N_("Test Pattern"),
-			"type", PURPLE_MEDIA_ELEMENT_VIDEO
-				| PURPLE_MEDIA_ELEMENT_SRC
-				| PURPLE_MEDIA_ELEMENT_ONE_SRC,
-			"create-cb", test_video_create_cb,
-			NULL));
-
-	for (sinks = VIDEO_SINK_PLUGINS; sinks[0]; sinks += 2) {
-		GstElementFactory *factory;
-
-		factory = gst_element_factory_find(sinks[0]);
-		if (!factory) {
-			continue;
-		}
-
-		purple_media_manager_register_element(manager,
-			g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
-				"id", sinks[0],
-				"name", sinks[1],
-				"type", PURPLE_MEDIA_ELEMENT_VIDEO
-					| PURPLE_MEDIA_ELEMENT_SINK
-					| PURPLE_MEDIA_ELEMENT_ONE_SINK,
-				"create-cb", gst_factory_make_cb,
-				NULL));
-
-		gst_object_unref(factory);
-	}
-}
-
-/*
- * PurpleMediaElementType
- */
-
-GType
-purple_media_element_type_get_type(void)
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GFlagsValue values[] = {
-			{ PURPLE_MEDIA_ELEMENT_NONE,
-				"PURPLE_MEDIA_ELEMENT_NONE", "none" },
-			{ PURPLE_MEDIA_ELEMENT_AUDIO,
-				"PURPLE_MEDIA_ELEMENT_AUDIO", "audio" },
-			{ PURPLE_MEDIA_ELEMENT_VIDEO,
-				"PURPLE_MEDIA_ELEMENT_VIDEO", "video" },
-			{ PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO,
-				"PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO",
-				"audio-video" },
-			{ PURPLE_MEDIA_ELEMENT_NO_SRCS,
-				"PURPLE_MEDIA_ELEMENT_NO_SRCS", "no-srcs" },
-			{ PURPLE_MEDIA_ELEMENT_ONE_SRC,
-				"PURPLE_MEDIA_ELEMENT_ONE_SRC", "one-src" },
-			{ PURPLE_MEDIA_ELEMENT_MULTI_SRC,
-				"PURPLE_MEDIA_ELEMENT_MULTI_SRC",
-				"multi-src" },
-			{ PURPLE_MEDIA_ELEMENT_REQUEST_SRC,
-				"PURPLE_MEDIA_ELEMENT_REQUEST_SRC",
-				"request-src" },
-			{ PURPLE_MEDIA_ELEMENT_NO_SINKS,
-				"PURPLE_MEDIA_ELEMENT_NO_SINKS", "no-sinks" },
-			{ PURPLE_MEDIA_ELEMENT_ONE_SINK,
-				"PURPLE_MEDIA_ELEMENT_ONE_SINK", "one-sink" },
-			{ PURPLE_MEDIA_ELEMENT_MULTI_SINK,
-				"PURPLE_MEDIA_ELEMENT_MULTI_SINK",
-				"multi-sink" },
-			{ PURPLE_MEDIA_ELEMENT_REQUEST_SINK,
-				"PURPLE_MEDIA_ELEMENT_REQUEST_SINK",
-				"request-sink" },
-			{ PURPLE_MEDIA_ELEMENT_UNIQUE,
-				"PURPLE_MEDIA_ELEMENT_UNIQUE", "unique" },
-			{ PURPLE_MEDIA_ELEMENT_SRC,
-				"PURPLE_MEDIA_ELEMENT_SRC", "src" },
-			{ PURPLE_MEDIA_ELEMENT_SINK,
-				"PURPLE_MEDIA_ELEMENT_SINK", "sink" },
-			{ PURPLE_MEDIA_ELEMENT_APPLICATION,
-				"PURPLE_MEDIA_ELEMENT_APPLICATION", "application" },
-			{ 0, NULL, NULL }
-		};
-		type = g_flags_register_static(
-				"PurpleMediaElementType", values);
-	}
-	return type;
-}
-
-/*
- * PurpleMediaElementInfo
- */
-
-struct _PurpleMediaElementInfoClass
-{
-	GObjectClass parent_class;
-};
-
-struct _PurpleMediaElementInfo
-{
-	GObject parent;
-};
-
-struct _PurpleMediaElementInfoPrivate
-{
-	gchar *id;
-	gchar *name;
-	PurpleMediaElementType type;
-	PurpleMediaElementCreateCallback create;
-};
-
-enum {
-	PROP_0,
-	PROP_ID,
-	PROP_NAME,
-	PROP_TYPE,
-	PROP_CREATE_CB,
-	N_PROPERTIES,
-};
-
-G_DEFINE_FINAL_TYPE_WITH_PRIVATE(PurpleMediaElementInfo,
-                                 purple_media_element_info, G_TYPE_OBJECT);
-
-static void
-purple_media_element_info_init(PurpleMediaElementInfo *info)
-{
-	PurpleMediaElementInfoPrivate *priv =
-			purple_media_element_info_get_instance_private(info);
-	priv->id = NULL;
-	priv->name = NULL;
-	priv->type = PURPLE_MEDIA_ELEMENT_NONE;
-	priv->create = NULL;
-}
-
-static void
-purple_media_element_info_finalize(GObject *info)
-{
-	PurpleMediaElementInfoPrivate *priv =
-			purple_media_element_info_get_instance_private(
-					PURPLE_MEDIA_ELEMENT_INFO(info));
-	g_free(priv->id);
-	g_free(priv->name);
-
-	G_OBJECT_CLASS(purple_media_element_info_parent_class)->finalize(info);
-}
-
-static void
-purple_media_element_info_set_property (GObject *object, guint prop_id,
-		const GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaElementInfoPrivate *priv;
-	g_return_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(object));
-
-	priv = purple_media_element_info_get_instance_private(
-			PURPLE_MEDIA_ELEMENT_INFO(object));
-
-	switch (prop_id) {
-		case PROP_ID:
-			g_free(priv->id);
-			priv->id = g_value_dup_string(value);
-			break;
-		case PROP_NAME:
-			g_free(priv->name);
-			priv->name = g_value_dup_string(value);
-			break;
-		case PROP_TYPE: {
-			priv->type = g_value_get_flags(value);
-			break;
-		}
-		case PROP_CREATE_CB:
-			priv->create = g_value_get_pointer(value);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_element_info_get_property (GObject *object, guint prop_id,
-		GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaElementInfoPrivate *priv;
-	g_return_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(object));
-
-	priv = purple_media_element_info_get_instance_private(
-			PURPLE_MEDIA_ELEMENT_INFO(object));
-
-	switch (prop_id) {
-		case PROP_ID:
-			g_value_set_string(value, priv->id);
-			break;
-		case PROP_NAME:
-			g_value_set_string(value, priv->name);
-			break;
-		case PROP_TYPE:
-			g_value_set_flags(value, priv->type);
-			break;
-		case PROP_CREATE_CB:
-			g_value_set_pointer(value, priv->create);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_element_info_class_init(PurpleMediaElementInfoClass *klass)
-{
-	GObjectClass *gobject_class = (GObjectClass*)klass;
-
-	gobject_class->finalize = purple_media_element_info_finalize;
-	gobject_class->set_property = purple_media_element_info_set_property;
-	gobject_class->get_property = purple_media_element_info_get_property;
-
-	/**
-	 * PurpleMediaElementInfo:id:
-	 *
-	 * The identifier for the element info.
-	 */
-	g_object_class_install_property(gobject_class, PROP_ID,
-			g_param_spec_string("id",
-			"ID",
-			"The unique identifier of the element.",
-			NULL,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaElementInfo:name:
-	 *
-	 * The name of the element info.
-	 */
-	g_object_class_install_property(gobject_class, PROP_NAME,
-			g_param_spec_string("name",
-			"Name",
-			"The friendly/display name of this element.",
-			NULL,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaElementInfo:type:
-	 *
-	 * The type of the element.
-	 */
-	g_object_class_install_property(gobject_class, PROP_TYPE,
-			g_param_spec_flags("type",
-			"Element Type",
-			"The type of element this is.",
-			PURPLE_TYPE_MEDIA_ELEMENT_TYPE,
-			PURPLE_MEDIA_ELEMENT_NONE,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS));
-
-	/**
-	 * PurpleMediaElementInfo:create-cb:
-	 *
-	 * A call back that is called when the element is created.
-	 */
-	g_object_class_install_property(gobject_class, PROP_CREATE_CB,
-			g_param_spec_pointer("create-cb",
-			"Create Callback",
-			"The function called to create this element.",
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-			G_PARAM_STATIC_STRINGS));
-}
-
-gchar *
-purple_media_element_info_get_id(PurpleMediaElementInfo *info)
-{
-	gchar *id;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), NULL);
-	g_object_get(info, "id", &id, NULL);
-	return id;
-}
-
-gchar *
-purple_media_element_info_get_name(PurpleMediaElementInfo *info)
-{
-	gchar *name;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), NULL);
-	g_object_get(info, "name", &name, NULL);
-	return name;
-}
-
-PurpleMediaElementType
-purple_media_element_info_get_element_type(PurpleMediaElementInfo *info)
-{
-	PurpleMediaElementType type;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info),
-			PURPLE_MEDIA_ELEMENT_NONE);
-	g_object_get(info, "type", &type, NULL);
-	return type;
-}
-
-GstElement *
-purple_media_element_info_call_create(PurpleMediaElementInfo *info,
-		PurpleMedia *media, const gchar *session_id,
-		const gchar *participant)
-{
-	PurpleMediaElementCreateCallback create;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), NULL);
-	g_object_get(info, "create-cb", &create, NULL);
-	if (create) {
-		return create(info, media, session_id, participant);
-	}
-	return NULL;
-}
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -5,12 +5,6 @@
 	'core.c',
 	'debug.c',
 	'image.c',
-	'media/backend-iface.c',
-	'media/candidate.c',
-	'media/codec.c',
-	'media/enum-types.c',
-	'media.c',
-	'mediamanager.c',
 	'network.c',
 	'notify.c',
 	'plugins.c',
@@ -64,7 +58,6 @@
 	'purpleprotocolconversation.c',
 	'purpleprotocolfiletransfer.c',
 	'purpleprotocolmanager.c',
-	'purpleprotocolmedia.c',
 	'purpleprotocolroster.c',
 	'purpleprotocolserver.c',
 	'purpleprotocolwhiteboard.c',
@@ -102,9 +95,6 @@
 	'core.h',
 	'debug.h',
 	'image.h',
-	'media.h',
-	'media-gst.h',
-	'mediamanager.h',
 	'network.h',
 	'notify.h',
 	'plugins.h',
@@ -157,7 +147,6 @@
 	'purpleprotocolcontacts.h',
 	'purpleprotocolconversation.h',
 	'purpleprotocolfiletransfer.h',
-	'purpleprotocolmedia.h',
 	'purpleprotocolmanager.h',
 	'purpleprotocolroster.h',
 	'purpleprotocolserver.h',
@@ -234,13 +223,6 @@
 	purple_coresources += windows.compile_resources(libpurplerc)
 endif
 
-purple_mediaheaders = [
-	'media/backend-iface.h',
-	'media/candidate.h',
-	'media/codec.h',
-	'media/enum-types.h'
-]
-
 purple_enumheaders = [
 	'connection.h',
 	'debug.h',
@@ -271,7 +253,7 @@
 enums_h = enums[1]
 
 PURPLE_H_INCLUDES = []
-foreach header : purple_coreheaders + purple_mediaheaders + purple_request_headers + ['purpleversionconsts.h', 'purpleenums.h']
+foreach header : purple_coreheaders + purple_request_headers + ['purpleversionconsts.h', 'purpleenums.h']
 	PURPLE_H_INCLUDES += f'#include <libpurple/@header@>'
 endforeach
 purple_h_conf = configuration_data()
@@ -316,9 +298,6 @@
 install_headers(purple_coreheaders,
                 subdir : purple_include_base)
 
-install_headers(purple_mediaheaders,
-                subdir : purple_include_base / 'media')
-
 install_headers(purple_request_headers,
                 subdir : purple_include_base / 'request')
 
@@ -337,7 +316,7 @@
 
 if enable_introspection
 	introspection_sources = (purple_coresources + purple_coreheaders +
-	                         purple_builtheaders + purple_mediaheaders + purple_request_headers)
+	                         purple_builtheaders + purple_request_headers)
 
 	libpurple_gir = gnome.generate_gir(libpurple,
 	    sources : introspection_sources,
@@ -375,5 +354,5 @@
 		meson.current_source_dir(),
 		'check_license_header_template.h',
 	] + ['glibcompat.h'] + purple_coresources + purple_coreheaders +
-	purple_mediaheaders + purple_private_headers + purple_request_headers)
+	purple_private_headers + purple_request_headers)
 
diff --git a/libpurple/purpleprotocolmedia.h b/libpurple/purpleprotocolmedia.h
deleted file mode 100644
--- a/libpurple/purpleprotocolmedia.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_PROTOCOL_MEDIA_H
-#define PURPLE_PROTOCOL_MEDIA_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "media.h"
-#include "purpleaccount.h"
-#include "purpleprotocol.h"
-#include "purpleversion.h"
-
-#define PURPLE_TYPE_PROTOCOL_MEDIA (purple_protocol_media_get_type())
-
-PURPLE_AVAILABLE_IN_3_0
-G_DECLARE_INTERFACE(PurpleProtocolMedia, purple_protocol_media, PURPLE,
-                    PROTOCOL_MEDIA, PurpleProtocol)
-
-G_BEGIN_DECLS
-
-/**
- * PurpleProtocolMedia:
- *
- * #PurpleProtocolMedia describes the multimedia api that is available for
- * protocols.
- *
- * Since: 3.0
- */
-
-struct _PurpleProtocolMediaInterface {
-	/*< private >*/
-	GTypeInterface parent;
-
-	/*< public >*/
-	gboolean (*initiate_session)(PurpleProtocolMedia *media, PurpleAccount *account, const gchar *who, PurpleMediaSessionType type);
-
-	PurpleMediaCaps (*get_caps)(PurpleProtocolMedia *media, PurpleAccount *account, const gchar *who);
-
-	gboolean (*send_dtmf)(PurpleProtocolMedia *protocol_media, PurpleMedia *media, gchar dtmf, guint8 volume, guint8 duration);
-
-	/*< private >*/
-	gpointer reserved[4];
-};
-
-/**
- * purple_protocol_media_initiate_session:
- * @media: The #PurpleProtocolMedia instance.
- * @account: The #PurpleAccount instance.
- * @who: The user to initiate a media session with.
- * @type: The type of media session to create.
- *
- * Initiates a media connection of @type to @who.
- *
- * Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-gboolean purple_protocol_media_initiate_session(PurpleProtocolMedia *media, PurpleAccount *account, const gchar *who, PurpleMediaSessionType type);
-
-/**
- * purple_protocol_media_get_caps:
- * @media: The #PurpleProtocolMedia instance.
- * @account: The #PurpleAccount instance.
- * @who: The user to get the media capabilities for.
- *
- * Gets the #PurpleMediaCaps for @who which determine what types of media are
- * available.
- *
- * Returns: the media capabilities of @who.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleMediaCaps purple_protocol_media_get_caps(PurpleProtocolMedia *media, PurpleAccount *account, const gchar *who);
-
-/**
- * purple_protocol_media_send_dtmf:
- * @protocol_media: The #PurpleProtocolMedia instance.
- * @media: The #PurpleMedia instance.
- * @dtmf: A DTMF to send.
- * @volume: The volume to send @dtmf at.
- * @duration: The duration to send @dtmf (in ms?)
- *
- * Sends a DTMF (dual-tone multi-frequency) signal via the established @media
- * for the given @duration at the given @volume.
- *
- * It is up to the specific implementation if DTMF is send in or out of band.
- *
- * Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-gboolean purple_protocol_media_send_dtmf(PurpleProtocolMedia *protocol_media, PurpleMedia *media, gchar dtmf, guint8 volume, guint8 duration);
-
-G_END_DECLS
-
-#endif /* PURPLE_PROTOCOL_MEDIA_H */
diff --git a/libpurple/purpleprotocolmedia.c b/libpurple/purpleprotocolmedia.c
deleted file mode 100644
--- a/libpurple/purpleprotocolmedia.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "purpleprotocolmedia.h"
-
-/******************************************************************************
- * GObject Implementation
- *****************************************************************************/
-G_DEFINE_INTERFACE(PurpleProtocolMedia, purple_protocol_media,
-                   PURPLE_TYPE_PROTOCOL)
-
-static void
-purple_protocol_media_default_init(G_GNUC_UNUSED PurpleProtocolMediaInterface *iface)
-{
-}
-
-/******************************************************************************
- * Public API
- *****************************************************************************/
-gboolean
-purple_protocol_media_initiate_session(PurpleProtocolMedia *media,
-                                       PurpleAccount *account,
-                                       const gchar *who,
-                                       PurpleMediaSessionType type)
-{
-	PurpleProtocolMediaInterface *iface = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_PROTOCOL_MEDIA(media), FALSE);
-
-	iface = PURPLE_PROTOCOL_MEDIA_GET_IFACE(media);
-	if(iface && iface->initiate_session) {
-		return iface->initiate_session(media, account, who, type);
-	}
-
-	return FALSE;
-}
-
-PurpleMediaCaps
-purple_protocol_media_get_caps(PurpleProtocolMedia *media,
-                               PurpleAccount *account, const gchar *who)
-{
-	PurpleProtocolMediaInterface *iface = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_PROTOCOL_MEDIA(media),
-	                     PURPLE_MEDIA_CAPS_NONE);
-
-	iface = PURPLE_PROTOCOL_MEDIA_GET_IFACE(media);
-	if(iface && iface->get_caps) {
-		return iface->get_caps(media, account, who);
-	}
-
-	return PURPLE_MEDIA_CAPS_NONE;
-}
-
-gboolean
-purple_protocol_media_send_dtmf(PurpleProtocolMedia *protocol_media,
-                                PurpleMedia *media, gchar dtmf, guint8 volume,
-                                guint8 duration)
-{
-	PurpleProtocolMediaInterface *iface = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_PROTOCOL_MEDIA(protocol_media), FALSE);
-
-	iface = PURPLE_PROTOCOL_MEDIA_GET_IFACE(protocol_media);
-	if(iface && iface->send_dtmf) {
-		return iface->send_dtmf(protocol_media, media, dtmf, volume, duration);
-	}
-
-	return FALSE;
-}
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -4,12 +4,6 @@
 libpurple/core.c
 libpurple/debug.c
 libpurple/image.c
-libpurple/media/backend-iface.c
-libpurple/media.c
-libpurple/media/candidate.c
-libpurple/media/codec.c
-libpurple/media/enum-types.c
-libpurple/mediamanager.c
 libpurple/network.c
 libpurple/notify.c
 libpurple/plugins/autoaccept/autoaccept.c
@@ -55,7 +49,6 @@
 libpurple/purpleprotocol.c
 libpurple/purpleprotocolclient.c
 libpurple/purpleprotocolmanager.c
-libpurple/purpleprotocolmedia.c
 libpurple/purpleprotocolserver.c
 libpurple/purpleprotocolwhiteboard.c
 libpurple/purplesqlitehistoryadapter.c
