RTSP audio stream + clock

Hey!

I tried creating RTSP stream with clock sync using audio stream, but audio stream stops after short time. Works on VLC without clock so I know its not stream issue, must be clock or my client.

My client:

#include <gst/gst.h>
#include <gst/net/gstnet.h>
#include <iostream>

#define PLAYBACK_DELAY_MS 100

// Callback to configure the source for synchronization
static void source_created(GstElement *pipe, GstElement *source) {
    g_object_set(source,
                 "latency", PLAYBACK_DELAY_MS,
                 "ntp-time-source", 3,  // Use NTP timestamps from RTP
                 "buffer-mode", 4,      // Sync buffer with the clock
                 "ntp-sync", TRUE,      // Enable NTP-based synchronization
                 NULL);
    std::cout << "Source configured for synchronization." << std::endl;
}

// Message handler for bus messages
static gboolean handle_message(GstBus *bus, GstMessage *message, gpointer user_data) {
    GMainLoop *loop = static_cast<GMainLoop *>(user_data);

    switch (GST_MESSAGE_TYPE(message)) {
        case GST_MESSAGE_ERROR: {
            GError *err = nullptr;
            gchar *debug_info = nullptr;
            gst_message_parse_error(message, &err, &debug_info);
            std::cerr << "Error received from element "
                      << GST_OBJECT_NAME(message->src)
                      << ": " << err->message << std::endl;
            if (debug_info) {
                std::cerr << "Debugging info: " << debug_info << std::endl;
            }
            g_clear_error(&err);
            g_free(debug_info);
            g_main_loop_quit(loop);
            break;
        }
        case GST_MESSAGE_WARNING: {
            GError *err = nullptr;
            gchar *debug_info = nullptr;
            gst_message_parse_warning(message, &err, &debug_info);
            std::cerr << "Warning received from element "
                      << GST_OBJECT_NAME(message->src)
                      << ": " << err->message << std::endl;
            if (debug_info) {
                std::cerr << "Debugging info: " << debug_info << std::endl;
            }
            g_clear_error(&err);
            g_free(debug_info);
            break;
        }
        case GST_MESSAGE_EOS:
            std::cerr << "Unexpected EOS received for a live stream. Ignoring it." << std::endl;
            break;
        default:
            break;
    }

    return TRUE;
}

int main(int argc, char *argv[]) {
    gst_init(&argc, &argv);

    if (argc < 4) {
        std::cerr << "Usage: " << argv[0]
                  << " <RTSP URI> <Clock IP> <Clock Port>" << std::endl;
        std::cerr << "Example: " << argv[0]
                  << " rtsp://192.168.0.90:8554/audio 192.168.0.90 8555" << std::endl;
        return -1;
    }

    const gchar *rtsp_uri = argv[1];
    const gchar *clock_ip = argv[2];
    gint clock_port = atoi(argv[3]);

    // Create the network clock
    GstClock *net_clock = gst_net_client_clock_new("net_clock", clock_ip, clock_port, 0);
    if (!net_clock) {
        std::cerr << "Failed to create net clock client for "
                  << clock_ip << ":" << clock_port << std::endl;
        return -1;
    }

    // Wait for the clock to stabilize
    if (!gst_clock_wait_for_sync(net_clock, 10 * GST_SECOND)) {
        std::cerr << "Failed to synchronize with the network clock" << std::endl;
        gst_object_unref(net_clock);
        return -1;
    }
    std::cout << "Network clock synchronized." << std::endl;

    // Create the playback pipeline
    GstElement *pipe = gst_element_factory_make("playbin", NULL);
    if (!pipe) {
        std::cerr << "Failed to create playbin element." << std::endl;
        gst_object_unref(net_clock);
        return -1;
    }

    g_object_set(pipe, "uri", rtsp_uri, NULL);

    // Use the network clock
    gst_pipeline_use_clock(GST_PIPELINE(pipe), net_clock);

    // Connect the source-created signal
    g_signal_connect(pipe, "source-setup", G_CALLBACK(source_created), NULL);

    // Create a GLib main loop
    GMainLoop *loop = g_main_loop_new(NULL, FALSE);

    // Add a bus watch to handle messages
    GstBus *bus = gst_element_get_bus(pipe);
    gst_bus_add_watch(bus, handle_message, loop);

    // Start playback
    if (gst_element_set_state(pipe, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
        std::cerr << "Failed to set pipeline to PLAYING state." << std::endl;
        gst_object_unref(bus);
        gst_object_unref(pipe);
        gst_object_unref(net_clock);
        g_main_loop_unref(loop);
        return -1;
    }
    std::cout << "Playing stream from: " << rtsp_uri << std::endl;

    // Run the main loop
    g_main_loop_run(loop);

    // Clean up
    gst_element_set_state(pipe, GST_STATE_NULL);
    gst_object_unref(bus);
    gst_object_unref(pipe);
    gst_object_unref(net_clock);
    g_main_loop_unref(loop);

    return 0;
}

My server:

#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
#include <gst/net/gstnettimeprovider.h>

int main(int argc, char *argv[]) {
    gst_init(&argc, &argv);

    // Obtain the global clock
    GstClock *global_clock = gst_system_clock_obtain();

    // Create a network time provider for the global clock
    gst_net_time_provider_new(global_clock, "0.0.0.0", 8555);

    // Create an RTSP server instance
    GstRTSPServer *server = gst_rtsp_server_new();

    // Bind the server to the specific IP address
    gst_rtsp_server_set_address(server, "0.0.0.0");

    // Get the mount points for this server
    GstRTSPMountPoints *mounts = gst_rtsp_server_get_mount_points(server);

    // Create a factory for the audio stream
    GstRTSPMediaFactory *factory = gst_rtsp_media_factory_new();

    // Define the pipeline for the audio stream
    const gchar *pipeline_str =
            "audiotestsrc is-live=true wave=sine freq=440 ! audioconvert ! "
            "audioresample ! rtpL16pay name=pay0 pt=96";
    gst_rtsp_media_factory_set_launch(factory, pipeline_str);

    // Set the clock for the media factory
    gst_rtsp_media_factory_set_clock(factory, global_clock);

    // Add the factory to the mount points
    gst_rtsp_mount_points_add_factory(mounts, "/audio", factory);
    g_object_unref(mounts);

    // Attach the server
    if (gst_rtsp_server_attach(server, NULL) == 0) {
        g_printerr("Failed to attach the RTSP server.\n");
        return -1;
    }

    g_print("RTSP server ready at rtsp://192.168.0.90:8554/audio\n");
    g_print("Clock is available at 192.168.0.90:8555\n");

    // Run the GLib main loop
    GMainLoop *loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(loop);

    // Clean up
    g_main_loop_unref(loop);
    g_object_unref(server);
    g_object_unref(global_clock);

    return 0;
}

Thank you in advance

I have tried to use GST_DEBUG and it responds wiht this

0:00:00.254987000 32064 0000023FCD4C1FA0 FIXME        rtpjitterbuffer gstrtpjitterbuffer.c:1664:gst_jitter_buffer_sink_p
arse_caps:<rtpjitterbuffer0> Unsupported media clock