2016-12-21 17:57:04 +01:00
|
|
|
#include "streamdiscoverer.h"
|
|
|
|
|
|
|
|
#include <gst/pbutils/pbutils.h>
|
2020-09-18 16:15:19 +02:00
|
|
|
|
|
|
|
#include <QEventLoop>
|
|
|
|
|
2016-12-21 17:57:04 +01:00
|
|
|
#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<StreamDiscoverer*>(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<StreamDiscoverer*>(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");
|
|
|
|
}
|
|
|
|
}
|