Sisyphus repository
Last update: 1 october 2023 | SRPMs: 18631 | Visits: 37865014
en ru br
ALT Linux repos
S:1.5-alt1.38416.2
D:1.0-alt35.27330.1
5.0: 1.0-alt35.27654.3
4.1: 1.0-alt35.26470.1
4.0: 1.0-alt35.23722.M40.1

Group :: Video
RPM: mplayer

 Main   Changelog   Spec   Patches   Sources   Download   Gear   Bugs and FR  Repocop 

Patch: mplayer-svn-r21128-pulseaudio.patch
Download


diff -urN mplayer-svn-r21128.orig/AUTHORS mplayer-svn-r21128/AUTHORS
--- mplayer-svn-r21128.orig/AUTHORS	2006-11-06 17:08:14 +0200
+++ mplayer-svn-r21128/AUTHORS	2006-11-21 17:27:58 +0200
@@ -627,6 +627,7 @@
 
 Poettering, Lennart <mzzcynlre@0pointer.de>
     * audio driver for the Polypaudio sound server
+    * audio driver for the PulseAudio sound server
 
 Poirier, Guillaume (poirierg) <poirierg@gmail.com>
     * French documentation translation and synchronization
diff -urN mplayer-svn-r21128.orig/configure mplayer-svn-r21128/configure
--- mplayer-svn-r21128.orig/configure	2006-11-21 15:37:21 +0200
+++ mplayer-svn-r21128/configure	2006-11-21 17:28:46 +0200
@@ -369,6 +369,7 @@
   --disable-arts         disable aRts audio output [autodetect]
   --disable-esd          disable esd audio output [autodetect]
   --disable-polyp        disable Polypaudio audio output [autodetect]
+  --disable-pulse        disable PulseAudio sound support [autodetect]
   --disable-jack         disable JACK audio output [autodetect]
   --disable-openal       disable OpenAL audio output [autodetect]
   --disable-nas          disable NAS audio output [autodetect]
@@ -1600,6 +1601,7 @@
 _arts=auto
 _esd=auto
 _polyp=auto
+_pulse=auto
 _jack=auto
 _openal=auto
 _libcdio=auto
@@ -1812,6 +1814,8 @@
   --disable-esd)	_esd=no		;;
   --enable-polyp)	_polyp=yes	;;
   --disable-polyp)	_polyp=no		;;
+  --enable-pulse)	_pulse=yes	;;
+  --disable-pulse)	_pulse=no	;;
   --enable-jack)	_jack=yes	;;
   --disable-jack)	_jack=no	;;
   --enable-openal)	_openal=yes	;;
@@ -4862,6 +4866,33 @@
 fi
 
 
+echocheck "Pulse"
+if test "$_pulse" = auto ; then
+  _pulse=no
+  if pkg-config --exists 'libpulse >= 0.9' ; then
+
+cat > $TMPC << EOF
+#include <pulse/pulseaudio.h>
+int main(void) { return 0; }
+EOF
+cc_check `pkg-config --libs --cflags libpulse` && tmp_run && _pulse=yes
+
+  fi
+fi
+echores "$_pulse"
+
+if test "$_pulse" = yes ; then
+  _def_pulse='#define USE_PULSE 1'
+  _aosrc="$_aosrc ao_pulse.c"
+  _aomodules="pulse $_aomodules"
+  _libs_mplayer="$_libs_mplayer `$_pkg_config --libs libpulse`"
+  _inc_extra="$_inc_extra `pkg-config --cflags libpulse`"
+else
+  _def_pulse='#undef USE_PULSE'
+  _noaomodules="pulse $_noaomodules"
+fi
+
+
 echocheck "JACK"
 if test "$_jack" = auto ; then
   _jack=yes
@@ -7876,6 +7907,7 @@
 $_def_esd
 $_def_esd_latency
 $_def_polyp
+$_def_pulse
 $_def_jack
 $_def_openal
 $_def_sys_asoundlib_h
diff -urN mplayer-svn-r21128.orig/libao2/ao_pulse.c mplayer-svn-r21128/libao2/ao_pulse.c
--- mplayer-svn-r21128.orig/libao2/ao_pulse.c	1970-01-01 03:00:00 +0300
+++ mplayer-svn-r21128/libao2/ao_pulse.c	2006-11-21 17:27:58 +0200
@@ -0,0 +1,566 @@
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "config.h"
+#include "libaf/af_format.h"
+#include "mp_msg.h"
+#include "audio_out.h"
+#include "audio_out_internal.h"
+
+#define	PULSE_CLIENT_NAME "MPlayer"
+
+/*#define PULSE_DEBUG*/
+
+/** General driver info */
+static ao_info_t info = {
+    "PulseAudio audio output",
+    "pulse",
+    "Lennart Poettering",
+    ""
+};
+
+/** The sink to connect to */
+static char *sink = NULL;
+
+/** PulseAudio playback stream object */
+static struct pa_stream *stream = NULL;
+
+/** PulseAudio connection context */
+static struct pa_context *context = NULL;
+
+/** Main event loop object */
+static struct pa_threaded_mainloop *mainloop = NULL;
+
+/** A temporary variable to store the current volume */
+static pa_cvolume volume;
+static int volume_initialized = 0;
+
+/** Some special libao macro magic */
+LIBAO_EXTERN(pulse)
+
+#define CHECK_DEAD_GOTO(label) do { \
+if (!context || pa_context_get_state(context) != PA_CONTEXT_READY || \
+    !stream || pa_stream_get_state(stream) != PA_STREAM_READY) { \
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Connection died: %s\n", context ? pa_strerror(pa_context_errno(context)) : "NULL"); \
+        goto label; \
+    }  \
+} while(0);
+
+static void context_state_cb(pa_context *c, void *userdata) {
+    assert(c);
+
+    switch (pa_context_get_state(c)) {
+        case PA_CONTEXT_READY:
+        case PA_CONTEXT_TERMINATED:
+        case PA_CONTEXT_FAILED:
+            pa_threaded_mainloop_signal(mainloop, 0);
+            break;
+
+        case PA_CONTEXT_UNCONNECTED:
+        case PA_CONTEXT_CONNECTING:
+        case PA_CONTEXT_AUTHORIZING:
+        case PA_CONTEXT_SETTING_NAME:
+            break;
+    }
+}
+
+static void stream_state_cb(pa_stream *s, void * userdata) {
+    assert(s);
+
+    switch (pa_stream_get_state(s)) {
+
+        case PA_STREAM_READY:
+        case PA_STREAM_FAILED:
+        case PA_STREAM_TERMINATED:
+            pa_threaded_mainloop_signal(mainloop, 0);
+            break;
+
+        case PA_STREAM_UNCONNECTED:
+        case PA_STREAM_CREATING:
+            break;
+    }
+}
+
+static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
+    assert(s);
+    
+    pa_threaded_mainloop_signal(mainloop, 0);
+}
+
+static void stream_latency_update_cb(pa_stream *s, void *userdata) {
+    assert(s);
+    
+    pa_threaded_mainloop_signal(mainloop, 0);
+}
+
+static void success_cb(pa_stream *s, int success, void *userdata) {
+    assert(s);
+
+    if (userdata)
+        *(int*) userdata = success;
+    pa_threaded_mainloop_signal(mainloop, 0);
+}
+
+/** libao initialization function, arguments are sampling frequency,
+ * number of channels, sample type and some flags */
+static int init(int rate_hz, int channels, int format, int flags) {
+    struct pa_sample_spec ss;
+    struct pa_channel_map map;
+    char hn[128];
+    char *host = NULL;
+
+    assert(!context);
+    assert(!stream);
+    assert(!mainloop);
+
+    if (ao_subdevice) {
+        int i = strcspn(ao_subdevice, ":");
+        if ((size_t) i >= sizeof(hn))
+            i = sizeof(hn)-1;
+
+        if (i > 0) {
+            strncpy(host = hn, ao_subdevice, i);
+            hn[i] = 0;
+        }
+
+        if (ao_subdevice[i] == ':')
+            sink = ao_subdevice+i+1;
+    }
+
+    ss.channels = channels;
+    ss.rate = rate_hz;
+
+    ao_data.samplerate = rate_hz;
+    ao_data.format = format;
+    ao_data.channels = channels;
+
+    switch (format) {
+        case AF_FORMAT_U8:
+            ss.format = PA_SAMPLE_U8;
+            break;
+        case AF_FORMAT_S16_LE:
+            ss.format = PA_SAMPLE_S16LE;
+            break;
+        case AF_FORMAT_S16_BE:
+            ss.format = PA_SAMPLE_S16BE;
+            break;
+        case AF_FORMAT_FLOAT_LE:
+            ss.format = PA_SAMPLE_FLOAT32LE;
+            break;
+        case AF_FORMAT_FLOAT_BE:
+            ss.format = PA_SAMPLE_FLOAT32BE;
+            break;
+        case AF_FORMAT_MU_LAW:
+            ss.format = PA_SAMPLE_ULAW;
+            break;
+        case AF_FORMAT_A_LAW:
+            ss.format = PA_SAMPLE_ALAW;
+            break;
+        default:
+            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Unsupported sample spec\n");
+            goto fail;
+    }
+
+    if (!pa_sample_spec_valid(&ss)) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Invalid sample spec\n");
+        goto fail;
+    }
+
+    pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
+    ao_data.bps = pa_bytes_per_second(&ss);
+
+    if (!volume_initialized || ss.channels != volume.channels) {
+        pa_cvolume_reset(&volume, ss.channels);
+        volume_initialized = 1;
+    }
+    
+    if (!(mainloop = pa_threaded_mainloop_new())) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate main loop\n");
+        goto fail;
+    }
+
+    if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), PULSE_CLIENT_NAME))) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate context\n");
+        goto fail;
+    }
+
+    pa_context_set_state_callback(context, context_state_cb, NULL);
+
+    if (pa_context_connect(context, host, 0, NULL) < 0) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
+        goto fail;
+    }
+
+    pa_threaded_mainloop_lock(mainloop);
+    
+    if (pa_threaded_mainloop_start(mainloop) < 0) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to start main loop\n");
+        goto unlock_and_fail;
+    }
+
+    /* Wait until the context is ready */
+    pa_threaded_mainloop_wait(mainloop);
+
+    if (pa_context_get_state(context) != PA_CONTEXT_READY) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
+        goto unlock_and_fail;
+    }
+
+    if (!(stream = pa_stream_new(context, "audio stream", &ss, &map))) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to create stream: %s\n", pa_strerror(pa_context_errno(context)));
+        goto unlock_and_fail;
+    }
+
+    pa_stream_set_state_callback(stream, stream_state_cb, NULL);
+    pa_stream_set_write_callback(stream, stream_request_cb, NULL);
+    pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL);
+
+    if (pa_stream_connect_playback(stream, sink, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, &volume, NULL) < 0) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect stream: %s\n", pa_strerror(pa_context_errno(context)));
+        goto unlock_and_fail;
+    }
+
+    /* Wait until the stream is ready */
+    pa_threaded_mainloop_wait(mainloop);
+
+    if (pa_stream_get_state(stream) != PA_STREAM_READY) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
+        goto unlock_and_fail;
+    }
+
+    pa_threaded_mainloop_unlock(mainloop);
+    
+    return 1;
+
+unlock_and_fail:
+
+    if (mainloop)
+        pa_threaded_mainloop_unlock(mainloop);
+    
+fail:
+    
+    uninit(1);
+    return 0;
+}
+
+/** Destroy libao driver */
+static void uninit(int immed) {
+#ifdef PULSE_DEBUG
+    fprintf(stderr, "uninit(%i) ***\n", immed); 
+#endif
+
+    if (stream) {
+        if (!immed) {
+            pa_operation *o;
+
+	    pa_threaded_mainloop_lock(mainloop);
+
+            if ((o = pa_stream_drain(stream, success_cb, NULL))) {
+
+                while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
+                    CHECK_DEAD_GOTO(fail);
+                    pa_threaded_mainloop_wait(mainloop);
+                }
+
+            fail:
+                
+                pa_operation_unref(o);
+            }
+
+	    pa_threaded_mainloop_unlock(mainloop);
+        }
+    }
+
+    if (mainloop)
+        pa_threaded_mainloop_stop(mainloop);
+    
+    if (stream) {
+        pa_stream_disconnect(stream);
+        pa_stream_unref(stream);
+        stream = NULL;
+    }
+
+    if (context) {
+        pa_context_disconnect(context);
+        pa_context_unref(context);
+        context = NULL;
+    }
+
+    if (mainloop) {
+        pa_threaded_mainloop_free(mainloop);
+        mainloop = NULL;
+    }
+}
+
+/** Play the specified data to the pulseaudio server */
+static int play(void* data, int len, int flags) {
+    int r = -1;
+    pa_operation *o = NULL;
+    
+    assert(stream);
+    assert(context);
+
+#ifdef PULSE_DEBUG
+    fprintf(stderr, "playing %lu ***\n", len); 
+#endif
+    
+    pa_threaded_mainloop_lock(mainloop);
+
+    CHECK_DEAD_GOTO(fail);
+
+    if (len) {
+
+        if (pa_stream_write(stream, data, len, NULL, 0, PA_SEEK_RELATIVE) < 0) {
+            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_write() failed: %s\n", pa_strerror(pa_context_errno(context)));
+            goto fail;
+        }
+        
+    } else {
+
+        if (!(o = pa_stream_trigger(stream, NULL, NULL))) {
+            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_trigger() failed: %s\n", pa_strerror(pa_context_errno(context)));
+            goto fail;
+        }
+
+        /* We don't wait for this operation to complete */
+    }
+
+    r = len;
+    
+fail:
+    if (o)
+        pa_operation_unref(o);
+
+    pa_threaded_mainloop_unlock(mainloop);
+    
+    return r;
+}
+
+static void cork(int b) {
+    pa_operation *o = NULL;
+    int success = 0;
+    
+    assert(stream);
+    assert(context);
+
+#ifdef PULSE_DEBUG
+    fprintf(stderr, "cork(%i) ***\n", b); 
+#endif
+    
+    pa_threaded_mainloop_lock(mainloop);
+
+    CHECK_DEAD_GOTO(fail);
+    
+    if (!(o = pa_stream_cork(stream, b, success_cb, &success))) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_cork() failed: %s\n", pa_strerror(pa_context_errno(context)));
+        goto fail;
+    }
+    
+    while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
+        CHECK_DEAD_GOTO(fail);
+        pa_threaded_mainloop_wait(mainloop);
+    }
+
+    if (!success) 
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_cork() failed: %s\n", pa_strerror(pa_context_errno(context)));
+    
+    pa_operation_unref(o);
+
+fail:
+    pa_threaded_mainloop_unlock(mainloop);
+}
+
+/** Pause the audio stream by corking it on the server */
+static void audio_pause(void) {
+    cork(1);
+ }
+
+/** Resume the audio stream by uncorking it on the server */
+static void audio_resume(void) {
+    cork(0);
+}
+
+/** Reset the audio stream, i.e. flush the playback buffer on the server side */
+static void reset(void) {
+    pa_operation *o = NULL;
+    int success = 0;
+    
+    assert(stream);
+    assert(context);
+
+#ifdef PULSE_DEBUG
+    fprintf(stderr, "reset() ***\n"); 
+#endif
+    
+    pa_threaded_mainloop_lock(mainloop);
+
+    CHECK_DEAD_GOTO(fail);
+    
+    if (!(o = pa_stream_flush(stream, success_cb, &success))) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_flush() failed: %s\n", pa_strerror(pa_context_errno(context)));
+        goto fail;
+    }
+    
+    while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
+        CHECK_DEAD_GOTO(fail);
+        pa_threaded_mainloop_wait(mainloop);
+    }
+
+    if (!success) 
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_flush() failed: %s\n", pa_strerror(pa_context_errno(context)));
+    
+    pa_operation_unref(o);
+
+fail:
+    pa_threaded_mainloop_unlock(mainloop);
+}
+
+/** Return number of bytes that may be written to the server without blocking */
+static int get_space(void) {
+    size_t l = (size_t) -1;
+
+    pa_threaded_mainloop_lock(mainloop);
+
+    CHECK_DEAD_GOTO(fail);
+
+    l = pa_stream_writable_size(stream);
+
+#ifdef PULSE_DEBUG
+    fprintf(stderr, "\nspace = %lu\n", l); 
+#endif
+
+fail:
+    
+    pa_threaded_mainloop_unlock(mainloop);
+
+    return l == (size_t) -1 ? -1 : (int) l;
+}
+
+/** Return the current latency in seconds */
+static float get_delay(void) {
+    pa_usec_t latency = (pa_usec_t) -1;
+
+    pa_threaded_mainloop_lock(mainloop);
+
+    for (;;) {
+        CHECK_DEAD_GOTO(fail);
+
+        if (pa_stream_get_latency(stream, &latency, NULL) >= 0)
+            break;
+
+        if (pa_context_errno(context) != PA_ERR_NODATA) {
+            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_get_latency() failed: %s\n", pa_strerror(pa_context_errno(context)));
+            goto fail;
+        }
+        
+        /* Wait until latency data is available again */
+        pa_threaded_mainloop_wait(mainloop);
+    }
+
+#ifdef PULSE_DEBUG
+    fprintf(stderr, "latency=%0.3f sec\n", (double) latency / 1000000); 
+#endif
+
+fail:
+    pa_threaded_mainloop_unlock(mainloop);
+
+    return (latency == (pa_usec_t) -1) ? 0 : ((float) latency / 1000000.0);
+}
+
+/** A callback function that is called when the
+ * pa_context_get_sink_input_info() operation completes. Saves the
+ * volume field of the specified structure to the global variable volume. */
+static void info_func(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) {
+    if (is_last < 0) {
+        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to get sink input info: %s\n", pa_strerror(pa_context_errno(context)));
+        return;
+    }
+
+    if (!i)
+        return;
+
+    volume = i->volume;
+    volume_initialized = 1;
+    
+    pa_threaded_mainloop_signal(mainloop, 0);
+}
+
+/** Issue special libao controls on the device */
+static int control(int cmd, void *arg) {
+    
+    if (!context || !stream)
+        return CONTROL_ERROR;
+    
+    switch (cmd) {
+        
+        case AOCONTROL_GET_VOLUME: {
+            /* Return the current volume of the playback stream */
+            ao_control_vol_t *vol = (ao_control_vol_t*) arg;
+            pa_operation *o;
+
+            if (!(o = pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_func, NULL))) {
+                mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_get_sink_input_info() failed: %s\n", pa_strerror(pa_context_errno(context)));
+                return CONTROL_ERROR;
+            }
+    
+            while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
+                CHECK_DEAD_GOTO(fail);
+                pa_threaded_mainloop_wait(mainloop);
+            }
+
+        fail:
+            pa_operation_unref(o);
+
+            if (!volume_initialized) {
+                mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_get_sink_input_info() failed: %s\n", pa_strerror(pa_context_errno(context)));
+                return CONTROL_ERROR;
+            }
+            
+            if (volume.channels != 2)
+                vol->left = vol->right = (int) ((pa_cvolume_avg(&volume)*100)/PA_VOLUME_NORM);
+            else {
+                vol->left = (int) (volume.values[0]*100)/PA_VOLUME_NORM;
+                vol->right = (int) (volume.values[1]*100)/PA_VOLUME_NORM;
+            }
+                
+            return CONTROL_OK;
+        }
+            
+        case AOCONTROL_SET_VOLUME: {
+            /* Set the playback volume of the stream */
+            const ao_control_vol_t *vol = (ao_control_vol_t*) arg;
+            pa_operation *o;
+
+            if (!volume_initialized) {
+                pa_cvolume_reset(&volume, 2);
+                volume_initialized = 1;
+            }
+            
+            if (volume.channels != 2)
+                pa_cvolume_set(&volume, volume.channels, ((pa_volume_t) vol->left*PA_VOLUME_NORM)/100);
+            else {
+                volume.values[0] = ((pa_volume_t) vol->left*PA_VOLUME_NORM)/100;
+                volume.values[1] = ((pa_volume_t) vol->right*PA_VOLUME_NORM)/100;
+            }
+
+            if (!(o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL))) {
+                mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_context_set_sink_input_volume() failed: %s\n", pa_strerror(pa_context_errno(context)));
+                return CONTROL_ERROR;
+            }
+
+            pa_operation_unref(o);
+
+            /* We don't wait for completion here */
+            
+            return CONTROL_OK;
+        }
+            
+        default:
+            /* Unknown CONTROL command */
+            return CONTROL_UNKNOWN;
+    }
+}
+
diff -urN mplayer-svn-r21128.orig/libao2/audio_out.c mplayer-svn-r21128/libao2/audio_out.c
--- mplayer-svn-r21128.orig/libao2/audio_out.c	2006-08-17 13:36:32 +0300
+++ mplayer-svn-r21128/libao2/audio_out.c	2006-11-21 17:27:58 +0200
@@ -28,6 +28,9 @@
 #ifdef USE_POLYP
 extern ao_functions_t audio_out_polyp;
 #endif
+#ifdef USE_PULSE
+extern ao_functions_t audio_out_pulse;
+#endif
 #ifdef USE_JACK
 extern ao_functions_t audio_out_jack;
 #endif
@@ -112,6 +115,9 @@
 #ifdef USE_POLYP
         &audio_out_polyp,
 #endif
+#ifdef USE_PULSE
+        &audio_out_pulse,
+#endif
 #ifdef USE_JACK
         &audio_out_jack,
 #endif
 
design & coding: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
current maintainer: Michael Shigorin