Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/audio_output/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 9 kB image not shown  

Quelle  vlcpulse.c   Sprache: C

 

/**
 * \file vlcpulse.c
 * \brief PulseAudio support library for LibVLC plugins
 */

/*****************************************************************************
 * Copyright (C) 2009-2011 Rémi Denis-Courmont
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <pulse/pulseaudio.h>

#include "audio_output/vlcpulse.h"
#include <assert.h>
#include <stdlib.h>
#include <locale.h>
#include <unistd.h>
#include <pwd.h>

#ifndef HAVE_PARTIAL_LINKING
const char vlc_module_name[] = "vlcpulse";
#endif

#undef vlc_pa_error
void vlc_pa_error (vlc_object_t *obj, const char *msg, pa_context *ctx)
{
    msg_Err (obj, "%s: %s", msg, pa_strerror (pa_context_errno (ctx)));
}

static void context_state_cb (pa_context *ctx, void *userdata)
{
    pa_threaded_mainloop *mainloop = userdata;

    switch (pa_context_get_state(ctx))
    {
        case PA_CONTEXT_READY:
        case PA_CONTEXT_FAILED:
        case PA_CONTEXT_TERMINATED:
            pa_threaded_mainloop_signal (mainloop, 0);
        default:
            break;
    }
}

static int context_wait(pa_context *ctx, pa_threaded_mainloop *mainloop)
{
    pa_context_state_t state;

    while ((state = pa_context_get_state (ctx)) != PA_CONTEXT_READY)
    {
        if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
            return -1;
        pa_threaded_mainloop_wait (mainloop);
    }
    return 0;
}

static void context_event_cb(pa_context *c, const char *name, pa_proplist *pl,
                             void *userdata)
{
    vlc_object_t *obj = userdata;

    msg_Warn (obj, "unhandled context event \"%s\"", name);
    (void) c;
    (void) pl;
}

/**
 * Initializes the PulseAudio main loop and connects to the PulseAudio server.
 * @return a PulseAudio context on success, or NULL on error
 */

pa_context *vlc_pa_connect (vlc_object_t *obj, pa_threaded_mainloop **mlp)
{
    msg_Dbg (obj, "using library version %s", pa_get_library_version ());
    msg_Dbg (obj, " (compiled with version %s, protocol %u)",
             pa_get_headers_version (), PA_PROTOCOL_VERSION);

    /* Initialize main loop */
    pa_threaded_mainloop *mainloop = pa_threaded_mainloop_new ();
    if (unlikely(mainloop == NULL))
        return NULL;

    if (pa_threaded_mainloop_start (mainloop) < 0)
    {
        pa_threaded_mainloop_free (mainloop);
        return NULL;
    }

    /* Fill in context (client) properties */
    char *ua = var_InheritString (obj, "user-agent");
    pa_proplist *props = pa_proplist_new ();
    if (likely(props != NULL))
    {
        char *str;

        if (ua != NULL)
            pa_proplist_sets (props, PA_PROP_APPLICATION_NAME, ua);

        str = var_InheritString (obj, "app-id");
        if (str != NULL)
        {
            pa_proplist_sets (props, PA_PROP_APPLICATION_ID, str);
            free (str);
        }
        str = var_InheritString (obj, "app-version");
        if (str != NULL)
        {
            pa_proplist_sets (props, PA_PROP_APPLICATION_VERSION, str);
            free (str);
        }
        str = var_InheritString (obj, "app-icon-name");
        if (str != NULL)
        {
            pa_proplist_sets (props, PA_PROP_APPLICATION_ICON_NAME, str);
            free (str);
        }
        //pa_proplist_sets (props, PA_PROP_APPLICATION_LANGUAGE, _("C"));
        pa_proplist_sets (props, PA_PROP_APPLICATION_LANGUAGE,
                          setlocale (LC_MESSAGES, NULL));

        pa_proplist_setf (props, PA_PROP_APPLICATION_PROCESS_ID, "%lu",
                          (unsigned long) getpid ());
        //pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_BINARY,
        //                  PACKAGE_NAME);

        for (size_t max = sysconf (_SC_GETPW_R_SIZE_MAX), len = max % 1024 + 1024;
             len < max; len += 1024)
        {
            struct passwd pwbuf, *pw;
            char buf[len];

            if (getpwuid_r (getuid (), &pwbuf, buf, sizeof (buf), &pw) == 0)
            {
                if (pw != NULL)
                    pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_USER,
                                      pw->pw_name);
                break;
            }
        }

        for (size_t max = sysconf (_SC_HOST_NAME_MAX), len = max % 1024 + 1024;
             len < max; len += 1024)
        {
            char hostname[len];

            if (gethostname (hostname, sizeof (hostname)) == 0)
            {
                pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_HOST,
                                  hostname);
                break;
            }
        }

        const char *session = getenv ("XDG_SESSION_COOKIE");
        if (session != NULL)
        {
            pa_proplist_setf (props, PA_PROP_APPLICATION_PROCESS_MACHINE_ID,
                              "%.32s", session); /* XXX: is this valid? */
            pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_SESSION_ID,
                              session);
        }
    }

    /* Connect to PulseAudio daemon */
    pa_context *ctx;
    pa_mainloop_api *api;

    pa_threaded_mainloop_lock (mainloop);
    api = pa_threaded_mainloop_get_api (mainloop);
    ctx = pa_context_new_with_proplist (api, ua, props);
    free (ua);
    if (props != NULL)
        pa_proplist_free (props);
    if (unlikely(ctx == NULL))
        goto fail;

    pa_context_set_state_callback (ctx, context_state_cb, mainloop);
    pa_context_set_event_callback (ctx, context_event_cb, obj);
    if (pa_context_connect (ctx, NULL, 0, NULL) < 0
     || context_wait (ctx, mainloop))
    {
        vlc_pa_error (obj, "PulseAudio server connection failure", ctx);
        pa_context_unref (ctx);
        goto fail;
    }
    msg_Dbg (obj, "connected %s to %s as client #%"PRIu32,
             pa_context_is_local (ctx) ? "locally" : "remotely",
             pa_context_get_server (ctx), pa_context_get_index (ctx));
    msg_Dbg (obj, "using protocol %"PRIu32", server protocol %"PRIu32,
             pa_context_get_protocol_version (ctx),
             pa_context_get_server_protocol_version (ctx));

    pa_threaded_mainloop_unlock (mainloop);
    *mlp = mainloop;
    return ctx;

fail:
    pa_threaded_mainloop_unlock (mainloop);
    pa_threaded_mainloop_stop (mainloop);
    pa_threaded_mainloop_free (mainloop);
    return NULL;
}

/**
 * Closes a connection to PulseAudio.
 */

void vlc_pa_disconnect (vlc_object_t *obj, pa_context *ctx,
                        pa_threaded_mainloop *mainloop)
{
    pa_threaded_mainloop_lock (mainloop);
    pa_context_disconnect (ctx);
    pa_context_set_event_callback (ctx, NULL, NULL);
    pa_context_set_state_callback (ctx, NULL, NULL);
    pa_context_unref (ctx);
    pa_threaded_mainloop_unlock (mainloop);

    pa_threaded_mainloop_stop (mainloop);
    pa_threaded_mainloop_free (mainloop);
    (void) obj;
}

/**
 * Frees a timer event.
 * \note Timer events can be created with pa_context_rttime_new().
 * \warning This function must be called from the mainloop,
 * or with the mainloop lock held.
 */

void vlc_pa_rttime_free (pa_threaded_mainloop *mainloop, pa_time_event *e)
{
    pa_mainloop_api *api = pa_threaded_mainloop_get_api (mainloop);

    api->time_free (e);
}

#undef vlc_pa_get_latency
/**
 * Gets latency of a PulseAudio stream.
 * \return the latency or VLC_TICK_INVALID on error.
 */

vlc_tick_t vlc_pa_get_latency(vlc_object_t *obj, pa_context *ctx, pa_stream *s)
{
    /* NOTE: pa_stream_get_latency() will report 0 rather than negative latency
     * when the write index of a playback stream is behind its read index.
     * playback streams. So use the lower-level pa_stream_get_timing_info()
     * directly to obtain the correct write index and convert it to a time,
     * and compute the correct latency value by subtracting the stream (read)
     * time.
     *
     * On the read side, pa_stream_get_time() is used instead of
     * pa_stream_get_timing_info() for the sake of interpolation. */

    const pa_sample_spec *ss = pa_stream_get_sample_spec(s);
    const pa_timing_info *ti = pa_stream_get_timing_info(s);

    if (ti == NULL) {
        msg_Dbg(obj, "no timing infos");
        return VLC_TICK_INVALID;
    }

    if (ti->write_index_corrupt) {
        msg_Dbg(obj, "write index corrupt");
        return VLC_TICK_INVALID;
    }

    pa_usec_t wt = pa_bytes_to_usec((uint64_t)ti->write_index, ss);
    pa_usec_t rt;

    if (pa_stream_get_time(s, &rt)) {
        if (pa_context_errno(ctx) != PA_ERR_NODATA)
            vlc_pa_error(obj, "unknown time", ctx);
        return VLC_TICK_INVALID;
    }

    union { uint64_t u; int64_t s; } d;
    d.u = wt - rt;
    return d.s; /* non-overflowing unsigned to signed conversion */
}

Messung
CHZG
839610093

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.