#include "streamdiscoverer.h" #include #include #include "core/logging.h" #include "core/signalchecker.h" #include "core/waitforsignal.h" const int StreamDiscoverer::kDiscoveryTimeoutS = 10; StreamDiscoverer::StreamDiscoverer() : QObject(nullptr) { // Setting up a discoverer: discoverer_ = gst_discoverer_new(kDiscoveryTimeoutS * GST_SECOND, NULL); if (discoverer_ == NULL) { qLog(Error) << "Error creating discoverer" << endl; return; } // Connecting its signals: CHECKED_GCONNECT(discoverer_, "discovered", &OnDiscovered, this); CHECKED_GCONNECT(discoverer_, "finished", &OnFinished, this); // Starting the discoverer process: gst_discoverer_start(discoverer_); } StreamDiscoverer::~StreamDiscoverer() { gst_discoverer_stop(discoverer_); g_object_unref(discoverer_); } void StreamDiscoverer::Discover(const QString& url) { // Adding the request to discover the url given as a parameter: qLog(Debug) << "Discover" << url; if (!gst_discoverer_discover_uri_async(discoverer_, url.toStdString().c_str())) { qLog(Error) << "Failed to start discovering" << url << endl; return; } WaitForSignal(this, SIGNAL(DiscoverFinished())); } void StreamDiscoverer::OnDiscovered(GstDiscoverer* discoverer, GstDiscovererInfo* info, GError* err, gpointer self) { StreamDiscoverer* instance = reinterpret_cast(self); QString discovered_url(gst_discoverer_info_get_uri(info)); GstDiscovererResult result = gst_discoverer_info_get_result(info); if (result != GST_DISCOVERER_OK) { QString error_message = GSTdiscovererErrorMessage(result); qLog(Error) << "Discovery failed:" << error_message << endl; emit instance->Error( tr("Error discovering %1: %2").arg(discovered_url).arg(error_message)); return; } // Get audio streams (we will only care about the first one, which should be // the only one). GList* audio_streams = gst_discoverer_info_get_audio_streams(info); if (audio_streams != nullptr) { qLog(Debug) << "Discovery successful" << endl; // We found a valid audio stream, extracting and saving its info: GstDiscovererStreamInfo* stream_audio_info = (GstDiscovererStreamInfo*)g_list_first(audio_streams)->data; StreamDetails stream_details; stream_details.url = discovered_url; stream_details.bitrate = gst_discoverer_audio_info_get_bitrate( GST_DISCOVERER_AUDIO_INFO(stream_audio_info)); stream_details.channels = gst_discoverer_audio_info_get_channels( GST_DISCOVERER_AUDIO_INFO(stream_audio_info)); stream_details.depth = gst_discoverer_audio_info_get_depth( GST_DISCOVERER_AUDIO_INFO(stream_audio_info)); stream_details.sample_rate = gst_discoverer_audio_info_get_sample_rate( GST_DISCOVERER_AUDIO_INFO(stream_audio_info)); // Human-readable codec name: GstCaps* stream_caps = gst_discoverer_stream_info_get_caps(stream_audio_info); gchar* decoder_description = gst_pb_utils_get_codec_description(stream_caps); stream_details.format = (decoder_description == NULL) ? QString(tr("Unknown")) : QString(decoder_description); gst_caps_unref(stream_caps); g_free(decoder_description); emit instance->DataReady(stream_details); } else { emit instance->Error( tr("Could not detect an audio stream in %1").arg(discovered_url)); } gst_discoverer_stream_info_list_free(audio_streams); } void StreamDiscoverer::OnFinished(GstDiscoverer* discoverer, gpointer self) { // The discoverer doesn't have any more urls in its queue. Let the loop know // it can exit. StreamDiscoverer* instance = reinterpret_cast(self); emit instance->DiscoverFinished(); } QString StreamDiscoverer::GSTdiscovererErrorMessage( GstDiscovererResult result) { switch (result) { case (GST_DISCOVERER_URI_INVALID): return tr("Invalid URL"); case (GST_DISCOVERER_TIMEOUT): return tr("Connection timed out"); case (GST_DISCOVERER_BUSY): return tr("The discoverer is busy"); case (GST_DISCOVERER_MISSING_PLUGINS): return tr("Missing plugins"); case (GST_DISCOVERER_ERROR): default: return tr("Could not get details"); } }