Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 183230 | Differences between
and this patch

Collapse All | Expand All

(-)mplayer-20070427.orig/AUTHORS (-1 / +1 lines)
Lines 629-635 Link Here
629
    * Darwin VCD/SVCD support
629
    * Darwin VCD/SVCD support
630
630
631
Poettering, Lennart <mzzcynlre@0pointer.de>
631
Poettering, Lennart <mzzcynlre@0pointer.de>
632
    * audio driver for the Polypaudio sound server
632
    * audio driver for the Pulseaudio sound server
633
633
634
Poirier, Guillaume (poirierg) <poirierg@gmail.com>
634
Poirier, Guillaume (poirierg) <poirierg@gmail.com>
635
    * French documentation translation and synchronization
635
    * French documentation translation and synchronization
(-)mplayer-20070427.orig/configure (-21 / +19 lines)
Lines 377-383 Link Here
377
  --disable-ossaudio     disable OSS audio output [autodetect]
377
  --disable-ossaudio     disable OSS audio output [autodetect]
378
  --disable-arts         disable aRts audio output [autodetect]
378
  --disable-arts         disable aRts audio output [autodetect]
379
  --disable-esd          disable esd audio output [autodetect]
379
  --disable-esd          disable esd audio output [autodetect]
380
  --disable-polyp        disable Polypaudio audio output [autodetect]
380
  --disable-pulse        disable Pulseaudio audio output [autodetect]
381
  --disable-jack         disable JACK audio output [autodetect]
381
  --disable-jack         disable JACK audio output [autodetect]
382
  --disable-openal       disable OpenAL audio output [autodetect]
382
  --disable-openal       disable OpenAL audio output [autodetect]
383
  --disable-nas          disable NAS audio output [autodetect]
383
  --disable-nas          disable NAS audio output [autodetect]
Lines 530-536 Link Here
530
_ossaudio=auto
530
_ossaudio=auto
531
_arts=auto
531
_arts=auto
532
_esd=auto
532
_esd=auto
533
_polyp=auto
533
_pulse=auto
534
_jack=auto
534
_jack=auto
535
_openal=auto
535
_openal=auto
536
_libcdio=auto
536
_libcdio=auto
Lines 844-851 Link Here
844
  --disable-arts)	_arts=no	;;
844
  --disable-arts)	_arts=no	;;
845
  --enable-esd)		_esd=yes	;;
845
  --enable-esd)		_esd=yes	;;
846
  --disable-esd)	_esd=no		;;
846
  --disable-esd)	_esd=no		;;
847
  --enable-polyp)	_polyp=yes	;;
847
  --enable-pulse)	_pulse=yes	;;
848
  --disable-polyp)	_polyp=no		;;
848
  --disable-pulse)	_pulse=no		;;
849
  --enable-jack)	_jack=yes	;;
849
  --enable-jack)	_jack=yes	;;
850
  --disable-jack)	_jack=no	;;
850
  --disable-jack)	_jack=no	;;
851
  --enable-openal)	_openal=yes	;;
851
  --enable-openal)	_openal=yes	;;
Lines 4936-4966 Link Here
4936
fi
4936
fi
4937
4937
4938
echocheck "Polyp"
4938
echocheck "Polyp"
4939
if test "$_polyp" = auto ; then
4939
if test "$_pulse" = auto ; then
4940
  _polyp=no
4940
  _pulse=no
4941
  if $_pkg_config --exists 'polyplib >= 0.6 polyplib-error >= 0.6 polyplib-mainloop >= 0.6' ; then
4941
  if $_pkg_config --exists 'libpulse >= 0.9' ; then
4942
4942
4943
cat > $TMPC << EOF
4943
cat > $TMPC << EOF
4944
#include <polyp/polyplib.h>
4944
#include <pulse/pulseaudio.h>
4945
#include <polyp/mainloop.h>
4946
#include <polyp/polyplib-error.h>
4947
int main(void) { return 0; }
4945
int main(void) { return 0; }
4948
EOF
4946
EOF
4949
cc_check `$_pkg_config --libs --cflags polyplib polyplib-error polyplib-mainloop` && tmp_run && _polyp=yes
4947
cc_check `$_pkg_config --libs --cflags libpulse` && tmp_run && _pulse=yes
4950
4948
4951
  fi
4949
  fi
4952
fi
4950
fi
4953
echores "$_polyp"
4951
echores "$_pulse"
4954
4952
4955
if test "$_polyp" = yes ; then
4953
if test "$_pulse" = yes ; then
4956
  _def_polyp='#define USE_POLYP 1'
4954
  _def_pulse='#define USE_PULSE 1'
4957
  _aosrc="$_aosrc ao_polyp.c"
4955
  _aosrc="$_aosrc ao_pulse.c"
4958
  _aomodules="polyp $_aomodules"
4956
  _aomodules="pulse $_aomodules"
4959
  _libs_mplayer="$_libs_mplayer `$_pkg_config --libs polyplib polyplib-error polyplib-mainloop`"
4957
  _libs_mplayer="$_libs_mplayer `$_pkg_config --libs libpulse`"
4960
  _inc_extra="$_inc_extra `$_pkg_config --cflags polyplib polyplib-error polyplib-mainloop`"
4958
  _inc_extra="$_inc_extra `$_pkg_config --cflags libpulse`"
4961
else
4959
else
4962
  _def_polyp='#undef USE_POLYP'
4960
  _def_pulse='#undef USE_PULSE'
4963
  _noaomodules="polyp $_noaomodules"
4961
  _noaomodules="pulse $_noaomodules"
4964
fi
4962
fi
4965
4963
4966
4964
Lines 8170-8176 Link Here
8170
$_def_arts
8168
$_def_arts
8171
$_def_esd
8169
$_def_esd
8172
$_def_esd_latency
8170
$_def_esd_latency
8173
$_def_polyp
8171
$_def_pulse
8174
$_def_jack
8172
$_def_jack
8175
$_def_openal
8173
$_def_openal
8176
$_def_openal_h
8174
$_def_openal_h
(-)mplayer-20070427.orig/libao2/ao_polyp.c (-324 lines)
Lines 1-324 Link Here
1
#include <assert.h>
2
#include <string.h>
3
4
#include <polyp/polyplib.h>
5
#include <polyp/polyplib-error.h>
6
#include <polyp/mainloop.h>
7
8
#include "config.h"
9
#include "audio_out.h"
10
#include "audio_out_internal.h"
11
#include "libaf/af_format.h"
12
#include "mp_msg.h"
13
14
#define	POLYP_CLIENT_NAME "MPlayer"
15
16
/** General driver info */
17
static ao_info_t info = {
18
    "Polypaudio audio output",
19
    "polyp",
20
    "Lennart Poettering",
21
    ""
22
};
23
24
/** The sink to connect to */
25
static char *sink = NULL;
26
27
/** Polypaudio playback stream object */
28
static struct pa_stream *stream = NULL;
29
30
/** Polypaudio connection context */
31
static struct pa_context *context = NULL;
32
33
/** Main event loop object */
34
static struct pa_mainloop *mainloop = NULL;
35
36
/** Some special libao macro magic */
37
LIBAO_EXTERN(polyp)
38
39
/** Wait until no further actions are pending on the connection context */
40
static void wait_for_completion(void) {
41
    assert(context && mainloop);
42
43
    while (pa_context_is_pending(context))
44
        pa_mainloop_iterate(mainloop, 1, NULL);
45
}
46
47
/** Make sure that the connection context doesn't starve to death */
48
static void keep_alive(void) {
49
    assert(context && mainloop);
50
51
    while (pa_mainloop_iterate(mainloop, 0, NULL) > 0);
52
}
53
54
/** Wait until the specified operation completes */
55
static void wait_for_operation(struct pa_operation *o) {
56
    assert(o && context && mainloop);
57
58
    while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
59
        pa_mainloop_iterate(mainloop, 1, NULL);
60
61
    pa_operation_unref(o);
62
}
63
64
/** libao initialization function, arguments are sampling frequency,
65
 * number of channels, sample type and some flags */
66
static int init(int rate_hz, int channels, int format, int flags) {
67
    struct pa_sample_spec ss;
68
    struct pa_buffer_attr a;
69
    char hn[128];
70
    char *host = NULL;
71
72
    assert(!context && !stream && !mainloop);
73
74
    if (ao_subdevice) {
75
        int i = strcspn(ao_subdevice, ":");
76
        if (i >= sizeof(hn))
77
            i = sizeof(hn)-1;
78
79
        if (i > 0) {
80
            strncpy(host = hn, ao_subdevice, i);
81
            hn[i] = 0;
82
        }
83
84
        if (ao_subdevice[i] == ':')
85
            sink = ao_subdevice+i+1;
86
    }
87
88
    mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] -%s-%s-\n", host, sink);
89
90
    
91
    ss.channels = channels;
92
    ss.rate = rate_hz;
93
94
    switch (format) {
95
        case AF_FORMAT_U8:
96
            ss.format = PA_SAMPLE_U8;
97
            break;
98
        case AF_FORMAT_S16_LE:
99
            ss.format = PA_SAMPLE_S16LE;
100
            break;
101
        case AF_FORMAT_S16_BE:
102
            ss.format = PA_SAMPLE_S16BE;
103
            break;
104
        case AF_FORMAT_FLOAT_NE:
105
            ss.format = PA_SAMPLE_FLOAT32;
106
            break;
107
        default:
108
            mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Unsupported sample spec\n");
109
            goto fail;
110
    }
111
112
113
    if (!pa_sample_spec_valid(&ss)) {
114
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Invalid sample spec\n");
115
        goto fail;
116
    }
117
        
118
119
    mainloop = pa_mainloop_new();
120
    assert(mainloop);
121
122
    context = pa_context_new(pa_mainloop_get_api(mainloop), POLYP_CLIENT_NAME);
123
    assert(context);
124
125
    pa_context_connect(context, host, 1, NULL);
126
127
    wait_for_completion();
128
129
    if (pa_context_get_state(context) != PA_CONTEXT_READY) {
130
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
131
        goto fail;
132
    }
133
134
    stream = pa_stream_new(context, "audio stream", &ss);
135
    assert(stream);
136
137
    a.maxlength = pa_bytes_per_second(&ss)*1;
138
    a.tlength = a.maxlength*9/10;
139
    a.prebuf = a.tlength/2;
140
    a.minreq = a.tlength/10;
141
    
142
    pa_stream_connect_playback(stream, sink, &a, PA_STREAM_INTERPOLATE_LATENCY, PA_VOLUME_NORM);
143
144
    wait_for_completion();
145
146
    if (pa_stream_get_state(stream) != PA_STREAM_READY) {
147
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
148
        goto fail;
149
    }
150
    
151
    return 1;
152
153
fail:
154
    uninit(1);
155
    return 0;
156
}
157
158
/** Destroy libao driver */
159
static void uninit(int immed) {
160
    if (stream) {
161
        if (!immed && pa_stream_get_state(stream) == PA_STREAM_READY)
162
                wait_for_operation(pa_stream_drain(stream, NULL, NULL));
163
        
164
        pa_stream_unref(stream);
165
        stream = NULL;
166
    }
167
168
    if (context) {
169
        pa_context_unref(context);
170
        context = NULL;
171
    }
172
173
    if (mainloop) {
174
        pa_mainloop_free(mainloop);
175
        mainloop = NULL;
176
    }
177
}
178
179
/** Play the specified data to the polypaudio server */
180
static int play(void* data, int len, int flags) {
181
    assert(stream && context);
182
183
    if (pa_stream_get_state(stream) != PA_STREAM_READY)
184
        return -1;
185
186
    if (!len)
187
        wait_for_operation(pa_stream_trigger(stream, NULL, NULL));
188
    else
189
        pa_stream_write(stream, data, len, NULL, 0);
190
191
    wait_for_completion();
192
193
    if (pa_stream_get_state(stream) != PA_STREAM_READY)
194
        return -1;
195
196
    return len;
197
}
198
199
/** Pause the audio stream by corking it on the server */
200
static void audio_pause(void) {
201
    assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
202
    wait_for_operation(pa_stream_cork(stream, 1, NULL, NULL));
203
}
204
205
/** Resume the audio stream by uncorking it on the server */
206
static void audio_resume(void) {
207
    assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
208
    wait_for_operation(pa_stream_cork(stream, 0, NULL, NULL));
209
}
210
211
/** Reset the audio stream, i.e. flush the playback buffer on the server side */
212
static void reset(void) {
213
    assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
214
    wait_for_operation(pa_stream_flush(stream, NULL, NULL));
215
}
216
217
/** Return number of bytes that may be written to the server without blocking */
218
static int get_space(void) {
219
    uint32_t l;
220
    assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
221
    
222
    keep_alive();
223
224
    l = pa_stream_writable_size(stream);
225
    
226
    return l;
227
}
228
229
/* A temporary latency variable */
230
/* static pa_usec_t latency = 0; */
231
232
/* static void latency_func(struct pa_stream *s, const struct pa_latency_info *l, void *userdata) { */
233
/*     int negative = 0; */
234
    
235
/*     if (!l) { */
236
/*         mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Invalid sample spec: %s\n", pa_strerror(pa_context_errno(context))); */
237
/*         return; */
238
/*     } */
239
240
/*     latency = pa_stream_get_latency(s, l, &negative); */
241
242
/*     /\* Nor really required *\/ */
243
/*     if (negative) */
244
/*         latency = 0; */
245
/* } */
246
247
/** Return the current latency in seconds */
248
static float get_delay(void) {
249
    pa_usec_t latency;
250
    assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
251
252
    /*     latency = 0; */
253
/*     wait_for_operation(pa_stream_get_latency(stream, latency_func, NULL)); */
254
    /*     pa_operation_unref(pa_stream_get_latency(stream, latency_func, NULL)); */
255
256
    latency = pa_stream_get_interpolated_latency(stream, NULL);
257
    
258
    return (float) latency/1000000;
259
}
260
261
/** A temporary variable to store the current volume */
262
static pa_volume_t volume = PA_VOLUME_NORM;
263
264
/** A callback function that is called when the
265
 * pa_context_get_sink_input_info() operation completes. Saves the
266
 * volume field of the specified structure to the global variable volume. */
267
static void info_func(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) {
268
    if (is_last < 0) {
269
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Failed to get sink input info: %s\n", pa_strerror(pa_context_errno(context)));
270
        return;
271
    }
272
273
    if (!i)
274
        return;
275
276
    volume = i->volume;
277
}
278
279
/** Issue special libao controls on the device */
280
static int control(int cmd, void *arg) {
281
    
282
    if (!context || !stream)
283
        return CONTROL_ERROR;
284
    
285
    switch (cmd) {
286
287
        case AOCONTROL_SET_DEVICE:
288
            /* Change the playback device */
289
            sink = (char*)arg;
290
            return CONTROL_OK;
291
292
        case AOCONTROL_GET_DEVICE:
293
            /* Return the playback device */
294
            *(char**)arg = sink;
295
            return CONTROL_OK;
296
        
297
        case AOCONTROL_GET_VOLUME: {
298
            /* Return the current volume of the playback stream */
299
            ao_control_vol_t *vol = (ao_control_vol_t*) arg;
300
                
301
            volume = PA_VOLUME_NORM;
302
            wait_for_operation(pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_func, NULL));
303
            vol->left = vol->right = (int) (pa_volume_to_user(volume)*100);
304
            return CONTROL_OK;
305
        }
306
            
307
        case AOCONTROL_SET_VOLUME: {
308
            /* Set the playback volume of the stream */
309
            const ao_control_vol_t *vol = (ao_control_vol_t*) arg;
310
            int v = vol->left;
311
            if (vol->right > v)
312
                v = vol->left;
313
            
314
            wait_for_operation(pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), pa_volume_from_user((double)v/100), NULL, NULL));
315
            
316
            return CONTROL_OK;
317
        }
318
            
319
        default:
320
            /* Unknown CONTROL command */
321
            return CONTROL_UNKNOWN;
322
    }
323
}
324
(-)mplayer-20070427.orig/libao2/ao_pulse.c (+565 lines)
Line 0 Link Here
1
#include <assert.h>
2
#include <string.h>
3
#include <stdio.h>
4
5
#include <pulse/pulseaudio.h>
6
7
#include "config.h"
8
#include "libaf/af_format.h"
9
#include "mp_msg.h"
10
#include "audio_out.h"
11
#include "audio_out_internal.h"
12
13
#define PULSE_CLIENT_NAME "MPlayer"
14
15
/*#define PULSE_DEBUG*/
16
17
/** General driver info */
18
static ao_info_t info = {
19
    "PulseAudio audio output",
20
    "pulse",
21
    "Lennart Poettering",
22
    ""
23
};
24
25
/** The sink to connect to */
26
static char *sink = NULL;
27
28
/** PulseAudio playback stream object */
29
static struct pa_stream *stream = NULL;
30
31
/** PulseAudio connection context */
32
static struct pa_context *context = NULL;
33
34
/** Main event loop object */
35
static struct pa_threaded_mainloop *mainloop = NULL;
36
37
/** A temporary variable to store the current volume */
38
static pa_cvolume volume;
39
static int volume_initialized = 0;
40
41
/** Some special libao macro magic */
42
LIBAO_EXTERN(pulse)
43
44
#define CHECK_DEAD_GOTO(label) do { \
45
if (!context || pa_context_get_state(context) != PA_CONTEXT_READY || \
46
    !stream || pa_stream_get_state(stream) != PA_STREAM_READY) { \
47
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Connection died: %s\n", context ? pa_strerror(pa_context_errno(context)) : "NULL"); \
48
        goto label; \
49
    }  \
50
} while(0);
51
52
static void context_state_cb(pa_context *c, void *userdata) {
53
    assert(c);
54
55
    switch (pa_context_get_state(c)) {
56
        case PA_CONTEXT_READY:
57
        case PA_CONTEXT_TERMINATED:
58
        case PA_CONTEXT_FAILED:
59
            pa_threaded_mainloop_signal(mainloop, 0);
60
            break;
61
62
        case PA_CONTEXT_UNCONNECTED:
63
        case PA_CONTEXT_CONNECTING:
64
        case PA_CONTEXT_AUTHORIZING:
65
        case PA_CONTEXT_SETTING_NAME:
66
            break;
67
    }
68
}
69
70
static void stream_state_cb(pa_stream *s, void * userdata) {
71
    assert(s);
72
73
    switch (pa_stream_get_state(s)) {
74
75
        case PA_STREAM_READY:
76
        case PA_STREAM_FAILED:
77
        case PA_STREAM_TERMINATED:
78
            pa_threaded_mainloop_signal(mainloop, 0);
79
            break;
80
81
        case PA_STREAM_UNCONNECTED:
82
        case PA_STREAM_CREATING:
83
            break;
84
    }
85
}
86
87
static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
88
    assert(s);
89
    
90
    pa_threaded_mainloop_signal(mainloop, 0);
91
}
92
93
static void stream_latency_update_cb(pa_stream *s, void *userdata) {
94
    assert(s);
95
    
96
    pa_threaded_mainloop_signal(mainloop, 0);
97
}
98
99
static void success_cb(pa_stream *s, int success, void *userdata) {
100
    assert(s);
101
102
    if (userdata)
103
        *(int*) userdata = success;
104
    pa_threaded_mainloop_signal(mainloop, 0);
105
}
106
107
/** libao initialization function, arguments are sampling frequency,
108
 * number of channels, sample type and some flags */
109
static int init(int rate_hz, int channels, int format, int flags) {
110
    struct pa_sample_spec ss;
111
    struct pa_channel_map map;
112
    char hn[128];
113
    char *host = NULL;
114
115
    assert(!context);
116
    assert(!stream);
117
    assert(!mainloop);
118
119
    if (ao_subdevice) {
120
        int i = strcspn(ao_subdevice, ":");
121
        if ((size_t) i >= sizeof(hn))
122
            i = sizeof(hn)-1;
123
124
        if (i > 0) {
125
            strncpy(host = hn, ao_subdevice, i);
126
            hn[i] = 0;
127
        }
128
129
        if (ao_subdevice[i] == ':')
130
            sink = ao_subdevice+i+1;
131
    }
132
133
    ss.channels = channels;
134
    ss.rate = rate_hz;
135
136
    ao_data.samplerate = rate_hz;
137
    ao_data.format = format;
138
    ao_data.channels = channels;
139
140
    switch (format) {
141
        case AF_FORMAT_U8:
142
            ss.format = PA_SAMPLE_U8;
143
            break;
144
        case AF_FORMAT_S16_LE:
145
            ss.format = PA_SAMPLE_S16LE;
146
            break;
147
        case AF_FORMAT_S16_BE:
148
            ss.format = PA_SAMPLE_S16BE;
149
            break;
150
        case AF_FORMAT_FLOAT_LE:
151
            ss.format = PA_SAMPLE_FLOAT32LE;
152
            break;
153
        case AF_FORMAT_FLOAT_BE:
154
            ss.format = PA_SAMPLE_FLOAT32BE;
155
            break;
156
        case AF_FORMAT_MU_LAW:
157
            ss.format = PA_SAMPLE_ULAW;
158
            break;
159
        case AF_FORMAT_A_LAW:
160
            ss.format = PA_SAMPLE_ALAW;
161
            break;
162
        default:
163
            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Unsupported sample spec\n");
164
            goto fail;
165
    }
166
167
    if (!pa_sample_spec_valid(&ss)) {
168
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Invalid sample spec\n");
169
        goto fail;
170
    }
171
172
    pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
173
    ao_data.bps = pa_bytes_per_second(&ss);
174
175
    if (!volume_initialized || ss.channels != volume.channels) {
176
        pa_cvolume_reset(&volume, ss.channels);
177
        volume_initialized = 1;
178
    }
179
    
180
    if (!(mainloop = pa_threaded_mainloop_new())) {
181
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate main loop\n");
182
        goto fail;
183
    }
184
185
    if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), PULSE_CLIENT_NAME))) {
186
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate context\n");
187
        goto fail;
188
    }
189
190
    pa_context_set_state_callback(context, context_state_cb, NULL);
191
192
    if (pa_context_connect(context, host, 0, NULL) < 0) {
193
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
194
        goto fail;
195
    }
196
197
    pa_threaded_mainloop_lock(mainloop);
198
    
199
    if (pa_threaded_mainloop_start(mainloop) < 0) {
200
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to start main loop\n");
201
        goto unlock_and_fail;
202
    }
203
204
    /* Wait until the context is ready */
205
    pa_threaded_mainloop_wait(mainloop);
206
207
    if (pa_context_get_state(context) != PA_CONTEXT_READY) {
208
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
209
        goto unlock_and_fail;
210
    }
211
212
    if (!(stream = pa_stream_new(context, "audio stream", &ss, &map))) {
213
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to create stream: %s\n", pa_strerror(pa_context_errno(context)));
214
        goto unlock_and_fail;
215
    }
216
217
    pa_stream_set_state_callback(stream, stream_state_cb, NULL);
218
    pa_stream_set_write_callback(stream, stream_request_cb, NULL);
219
    pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL);
220
221
    if (pa_stream_connect_playback(stream, sink, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, &volume, NULL) < 0) {
222
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect stream: %s\n", pa_strerror(pa_context_errno(context)));
223
        goto unlock_and_fail;
224
    }
225
226
    /* Wait until the stream is ready */
227
    pa_threaded_mainloop_wait(mainloop);
228
229
    if (pa_stream_get_state(stream) != PA_STREAM_READY) {
230
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
231
        goto unlock_and_fail;
232
    }
233
234
    pa_threaded_mainloop_unlock(mainloop);
235
    
236
    return 1;
237
238
unlock_and_fail:
239
240
    if (mainloop)
241
        pa_threaded_mainloop_unlock(mainloop);
242
    
243
fail:
244
    
245
    uninit(1);
246
    return 0;
247
}
248
249
/** Destroy libao driver */
250
static void uninit(int immed) {
251
#ifdef PULSE_DEBUG
252
    fprintf(stderr, "uninit(%i) ***\n", immed); 
253
#endif
254
255
    if (stream) {
256
        if (!immed) {
257
            pa_operation *o;
258
259
        pa_threaded_mainloop_lock(mainloop);
260
261
            if ((o = pa_stream_drain(stream, success_cb, NULL))) {
262
263
                while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
264
                    CHECK_DEAD_GOTO(fail);
265
                    pa_threaded_mainloop_wait(mainloop);
266
                }
267
268
            fail:
269
                
270
                pa_operation_unref(o);
271
            }
272
273
        pa_threaded_mainloop_unlock(mainloop);
274
        }
275
    }
276
277
    if (mainloop)
278
        pa_threaded_mainloop_stop(mainloop);
279
    
280
    if (stream) {
281
        pa_stream_disconnect(stream);
282
        pa_stream_unref(stream);
283
        stream = NULL;
284
    }
285
286
    if (context) {
287
        pa_context_disconnect(context);
288
        pa_context_unref(context);
289
        context = NULL;
290
    }
291
292
    if (mainloop) {
293
        pa_threaded_mainloop_free(mainloop);
294
        mainloop = NULL;
295
    }
296
}
297
298
/** Play the specified data to the pulseaudio server */
299
static int play(void* data, int len, int flags) {
300
    int r = -1;
301
    pa_operation *o = NULL;
302
    
303
    assert(stream);
304
    assert(context);
305
306
#ifdef PULSE_DEBUG
307
    fprintf(stderr, "playing %lu ***\n", len); 
308
#endif
309
    
310
    pa_threaded_mainloop_lock(mainloop);
311
312
    CHECK_DEAD_GOTO(fail);
313
314
    if (len) {
315
316
        if (pa_stream_write(stream, data, len, NULL, 0, PA_SEEK_RELATIVE) < 0) {
317
            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_write() failed: %s\n", pa_strerror(pa_context_errno(context)));
318
            goto fail;
319
        }
320
        
321
    } else {
322
323
        if (!(o = pa_stream_trigger(stream, NULL, NULL))) {
324
            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_trigger() failed: %s\n", pa_strerror(pa_context_errno(context)));
325
            goto fail;
326
        }
327
328
        /* We don't wait for this operation to complete */
329
    }
330
331
    r = len;
332
    
333
fail:
334
    if (o)
335
        pa_operation_unref(o);
336
337
    pa_threaded_mainloop_unlock(mainloop);
338
    
339
    return r;
340
}
341
342
static void cork(int b) {
343
    pa_operation *o = NULL;
344
    int success = 0;
345
    
346
    assert(stream);
347
    assert(context);
348
349
#ifdef PULSE_DEBUG
350
    fprintf(stderr, "cork(%i) ***\n", b); 
351
#endif
352
    
353
    pa_threaded_mainloop_lock(mainloop);
354
355
    CHECK_DEAD_GOTO(fail);
356
    
357
    if (!(o = pa_stream_cork(stream, b, success_cb, &success))) {
358
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_cork() failed: %s\n", pa_strerror(pa_context_errno(context)));
359
        goto fail;
360
    }
361
    
362
    while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
363
        CHECK_DEAD_GOTO(fail);
364
        pa_threaded_mainloop_wait(mainloop);
365
    }
366
367
    if (!success) 
368
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_cork() failed: %s\n", pa_strerror(pa_context_errno(context)));
369
    
370
    pa_operation_unref(o);
371
372
fail:
373
    pa_threaded_mainloop_unlock(mainloop);
374
}
375
376
/** Pause the audio stream by corking it on the server */
377
static void audio_pause(void) {
378
    cork(1);
379
 }
380
381
/** Resume the audio stream by uncorking it on the server */
382
static void audio_resume(void) {
383
    cork(0);
384
}
385
386
/** Reset the audio stream, i.e. flush the playback buffer on the server side */
387
static void reset(void) {
388
    pa_operation *o = NULL;
389
    int success = 0;
390
    
391
    assert(stream);
392
    assert(context);
393
394
#ifdef PULSE_DEBUG
395
    fprintf(stderr, "reset() ***\n"); 
396
#endif
397
    
398
    pa_threaded_mainloop_lock(mainloop);
399
400
    CHECK_DEAD_GOTO(fail);
401
    
402
    if (!(o = pa_stream_flush(stream, success_cb, &success))) {
403
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_flush() failed: %s\n", pa_strerror(pa_context_errno(context)));
404
        goto fail;
405
    }
406
    
407
    while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
408
        CHECK_DEAD_GOTO(fail);
409
        pa_threaded_mainloop_wait(mainloop);
410
    }
411
412
    if (!success) 
413
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_flush() failed: %s\n", pa_strerror(pa_context_errno(context)));
414
    
415
    pa_operation_unref(o);
416
417
fail:
418
    pa_threaded_mainloop_unlock(mainloop);
419
}
420
421
/** Return number of bytes that may be written to the server without blocking */
422
static int get_space(void) {
423
    size_t l = (size_t) -1;
424
425
    pa_threaded_mainloop_lock(mainloop);
426
427
    CHECK_DEAD_GOTO(fail);
428
429
    l = pa_stream_writable_size(stream);
430
431
#ifdef PULSE_DEBUG
432
    fprintf(stderr, "\nspace = %lu\n", l); 
433
#endif
434
435
fail:
436
    
437
    pa_threaded_mainloop_unlock(mainloop);
438
439
    return l == (size_t) -1 ? -1 : (int) l;
440
}
441
442
/** Return the current latency in seconds */
443
static float get_delay(void) {
444
    pa_usec_t latency = (pa_usec_t) -1;
445
446
    pa_threaded_mainloop_lock(mainloop);
447
448
    for (;;) {
449
        CHECK_DEAD_GOTO(fail);
450
451
        if (pa_stream_get_latency(stream, &latency, NULL) >= 0)
452
            break;
453
454
        if (pa_context_errno(context) != PA_ERR_NODATA) {
455
            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_get_latency() failed: %s\n", pa_strerror(pa_context_errno(context)));
456
            goto fail;
457
        }
458
        
459
        /* Wait until latency data is available again */
460
        pa_threaded_mainloop_wait(mainloop);
461
    }
462
463
#ifdef PULSE_DEBUG
464
    fprintf(stderr, "latency=%0.3f sec\n", (double) latency / 1000000); 
465
#endif
466
467
fail:
468
    pa_threaded_mainloop_unlock(mainloop);
469
470
    return (latency == (pa_usec_t) -1) ? 0 : ((float) latency / 1000000.0);
471
}
472
473
/** A callback function that is called when the
474
 * pa_context_get_sink_input_info() operation completes. Saves the
475
 * volume field of the specified structure to the global variable volume. */
476
static void info_func(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) {
477
    if (is_last < 0) {
478
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to get sink input info: %s\n", pa_strerror(pa_context_errno(context)));
479
        return;
480
    }
481
482
    if (!i)
483
        return;
484
485
    volume = i->volume;
486
    volume_initialized = 1;
487
    
488
    pa_threaded_mainloop_signal(mainloop, 0);
489
}
490
491
/** Issue special libao controls on the device */
492
static int control(int cmd, void *arg) {
493
    
494
    if (!context || !stream)
495
        return CONTROL_ERROR;
496
    
497
    switch (cmd) {
498
        
499
        case AOCONTROL_GET_VOLUME: {
500
            /* Return the current volume of the playback stream */
501
            ao_control_vol_t *vol = (ao_control_vol_t*) arg;
502
            pa_operation *o;
503
504
            if (!(o = pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_func, NULL))) {
505
                mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_get_sink_input_info() failed: %s\n", pa_strerror(pa_context_errno(context)));
506
                return CONTROL_ERROR;
507
            }
508
    
509
            while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
510
                CHECK_DEAD_GOTO(fail);
511
                pa_threaded_mainloop_wait(mainloop);
512
            }
513
514
        fail:
515
            pa_operation_unref(o);
516
517
            if (!volume_initialized) {
518
                mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_get_sink_input_info() failed: %s\n", pa_strerror(pa_context_errno(context)));
519
                return CONTROL_ERROR;
520
            }
521
            
522
            if (volume.channels != 2)
523
                vol->left = vol->right = (int) ((pa_cvolume_avg(&volume)*100)/PA_VOLUME_NORM);
524
            else {
525
                vol->left = (int) (volume.values[0]*100)/PA_VOLUME_NORM;
526
                vol->right = (int) (volume.values[1]*100)/PA_VOLUME_NORM;
527
            }
528
                
529
            return CONTROL_OK;
530
        }
531
            
532
        case AOCONTROL_SET_VOLUME: {
533
            /* Set the playback volume of the stream */
534
            const ao_control_vol_t *vol = (ao_control_vol_t*) arg;
535
            pa_operation *o;
536
537
            if (!volume_initialized) {
538
                pa_cvolume_reset(&volume, 2);
539
                volume_initialized = 1;
540
            }
541
            
542
            if (volume.channels != 2)
543
                pa_cvolume_set(&volume, volume.channels, ((pa_volume_t) vol->left*PA_VOLUME_NORM)/100);
544
            else {
545
                volume.values[0] = ((pa_volume_t) vol->left*PA_VOLUME_NORM)/100;
546
                volume.values[1] = ((pa_volume_t) vol->right*PA_VOLUME_NORM)/100;
547
            }
548
549
            if (!(o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL))) {
550
                mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_context_set_sink_input_volume() failed: %s\n", pa_strerror(pa_context_errno(context)));
551
                return CONTROL_ERROR;
552
            }
553
554
            pa_operation_unref(o);
555
556
            /* We don't wait for completion here */
557
            
558
            return CONTROL_OK;
559
        }
560
            
561
        default:
562
            /* Unknown CONTROL command */
563
            return CONTROL_UNKNOWN;
564
    }
565
}
(-)mplayer-20070427.orig/libao2/ao_pulse.c~ (+565 lines)
Line 0 Link Here
1
#include <assert.h>
2
#include <string.h>
3
#include <stdio.h>
4
5
#include <pulse/pulseaudio.h>
6
7
#include "config.h"
8
#include "libaf/af_format.h"
9
#include "mp_msg.h"
10
#include "audio_out.h"
11
#include "audio_out_internal.h"
12
13
#define PULSE_CLIENT_NAME "MPlayer"
14
15
/*#define PULSE_DEBUG*/
16
17
/** General driver info */
18
static ao_info_t info = {
19
    "PulseAudio audio output",
20
    "pulse",
21
    "Lennart Poettering",
22
    ""
23
};
24
25
/** The sink to connect to */
26
static char *sink = NULL;
27
28
/** PulseAudio playback stream object */
29
static struct pa_stream *stream = NULL;
30
31
/** PulseAudio connection context */
32
static struct pa_context *context = NULL;
33
34
/** Main event loop object */
35
static struct pa_threaded_mainloop *mainloop = NULL;
36
37
/** A temporary variable to store the current volume */
38
static pa_cvolume volume;
39
static int volume_initialized = 0;
40
41
/** Some special libao macro magic */
42
LIBAO_EXTERN(pulse)
43
44
#define CHECK_DEAD_GOTO(label) do { \
45
if (!context || pa_context_get_state(context) != PA_CONTEXT_READY || \
46
    !stream || pa_stream_get_state(stream) != PA_STREAM_READY) { \
47
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Connection died: %s\n", context ? pa_strerror(pa_context_errno(context)) : "NULL"); \
48
        goto label; \
49
    }  \
50
} while(0);
51
52
static void context_state_cb(pa_context *c, void *userdata) {
53
    assert(c);
54
55
    switch (pa_context_get_state(c)) {
56
        case PA_CONTEXT_READY:
57
        case PA_CONTEXT_TERMINATED:
58
        case PA_CONTEXT_FAILED:
59
            pa_threaded_mainloop_signal(mainloop, 0);
60
            break;
61
62
        case PA_CONTEXT_UNCONNECTED:
63
        case PA_CONTEXT_CONNECTING:
64
        case PA_CONTEXT_AUTHORIZING:
65
        case PA_CONTEXT_SETTING_NAME:
66
            break;
67
    }
68
}
69
70
static void stream_state_cb(pa_stream *s, void * userdata) {
71
    assert(s);
72
73
    switch (pa_stream_get_state(s)) {
74
75
        case PA_STREAM_READY:
76
        case PA_STREAM_FAILED:
77
        case PA_STREAM_TERMINATED:
78
            pa_threaded_mainloop_signal(mainloop, 0);
79
            break;
80
81
        case PA_STREAM_UNCONNECTED:
82
        case PA_STREAM_CREATING:
83
            break;
84
    }
85
}
86
87
static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
88
    assert(s);
89
    
90
    pa_threaded_mainloop_signal(mainloop, 0);
91
}
92
93
static void stream_latency_update_cb(pa_stream *s, void *userdata) {
94
    assert(s);
95
    
96
    pa_threaded_mainloop_signal(mainloop, 0);
97
}
98
99
static void success_cb(pa_stream *s, int success, void *userdata) {
100
    assert(s);
101
102
    if (userdata)
103
        *(int*) userdata = success;
104
    pa_threaded_mainloop_signal(mainloop, 0);
105
}
106
107
/** libao initialization function, arguments are sampling frequency,
108
 * number of channels, sample type and some flags */
109
static int init(int rate_hz, int channels, int format, int flags) {
110
    struct pa_sample_spec ss;
111
    struct pa_channel_map map;
112
    char hn[128];
113
    char *host = NULL;
114
115
    assert(!context);
116
    assert(!stream);
117
    assert(!mainloop);
118
119
    if (ao_subdevice) {
120
        int i = strcspn(ao_subdevice, ":");
121
        if ((size_t) i >= sizeof(hn))
122
            i = sizeof(hn)-1;
123
124
        if (i > 0) {
125
            strncpy(host = hn, ao_subdevice, i);
126
            hn[i] = 0;
127
        }
128
129
        if (ao_subdevice[i] == ':')
130
            sink = ao_subdevice+i+1;
131
    }
132
133
    ss.channels = channels;
134
    ss.rate = rate_hz;
135
136
    ao_data.samplerate = rate_hz;
137
    ao_data.format = format;
138
    ao_data.channels = channels;
139
140
    switch (format) {
141
        case AF_FORMAT_U8:
142
            ss.format = PA_SAMPLE_U8;
143
            break;
144
        case AF_FORMAT_S16_LE:
145
            ss.format = PA_SAMPLE_S16LE;
146
            break;
147
        case AF_FORMAT_S16_BE:
148
            ss.format = PA_SAMPLE_S16BE;
149
            break;
150
        case AF_FORMAT_FLOAT_LE:
151
            ss.format = PA_SAMPLE_FLOAT32LE;
152
            break;
153
        case AF_FORMAT_FLOAT_BE:
154
            ss.format = PA_SAMPLE_FLOAT32BE;
155
            break;
156
        case AF_FORMAT_MU_LAW:
157
            ss.format = PA_SAMPLE_ULAW;
158
            break;
159
        case AF_FORMAT_A_LAW:
160
            ss.format = PA_SAMPLE_ALAW;
161
            break;
162
        default:
163
            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Unsupported sample spec\n");
164
            goto fail;
165
    }
166
167
    if (!pa_sample_spec_valid(&ss)) {
168
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Invalid sample spec\n");
169
        goto fail;
170
    }
171
172
    pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
173
    ao_data.bps = pa_bytes_per_second(&ss);
174
175
    if (!volume_initialized || ss.channels != volume.channels) {
176
        pa_cvolume_reset(&volume, ss.channels);
177
        volume_initialized = 1;
178
    }
179
    
180
    if (!(mainloop = pa_threaded_mainloop_new())) {
181
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate main loop\n");
182
        goto fail;
183
    }
184
185
    if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), PULSE_CLIENT_NAME))) {
186
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate context\n");
187
        goto fail;
188
    }
189
190
    pa_context_set_state_callback(context, context_state_cb, NULL);
191
192
    if (pa_context_connect(context, host, 0, NULL) < 0) {
193
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
194
        goto fail;
195
    }
196
197
    pa_threaded_mainloop_lock(mainloop);
198
    
199
    if (pa_threaded_mainloop_start(mainloop) < 0) {
200
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to start main loop\n");
201
        goto unlock_and_fail;
202
    }
203
204
    /* Wait until the context is ready */
205
    pa_threaded_mainloop_wait(mainloop);
206
207
    if (pa_context_get_state(context) != PA_CONTEXT_READY) {
208
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
209
        goto unlock_and_fail;
210
    }
211
212
    if (!(stream = pa_stream_new(context, "audio stream", &ss, &map))) {
213
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to create stream: %s\n", pa_strerror(pa_context_errno(context)));
214
        goto unlock_and_fail;
215
    }
216
217
    pa_stream_set_state_callback(stream, stream_state_cb, NULL);
218
    pa_stream_set_write_callback(stream, stream_request_cb, NULL);
219
    pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL);
220
221
    if (pa_stream_connect_playback(stream, sink, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, &volume, NULL) < 0) {
222
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect stream: %s\n", pa_strerror(pa_context_errno(context)));
223
        goto unlock_and_fail;
224
    }
225
226
    /* Wait until the stream is ready */
227
    pa_threaded_mainloop_wait(mainloop);
228
229
    if (pa_stream_get_state(stream) != PA_STREAM_READY) {
230
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
231
        goto unlock_and_fail;
232
    }
233
234
    pa_threaded_mainloop_unlock(mainloop);
235
    
236
    return 1;
237
238
unlock_and_fail:
239
240
    if (mainloop)
241
        pa_threaded_mainloop_unlock(mainloop);
242
    
243
fail:
244
    
245
    uninit(1);
246
    return 0;
247
}
248
249
/** Destroy libao driver */
250
static void uninit(int immed) {
251
#ifdef PULSE_DEBUG
252
    fprintf(stderr, "uninit(%i) ***\n", immed); 
253
#endif
254
255
    if (stream) {
256
        if (!immed) {
257
            pa_operation *o;
258
259
        pa_threaded_mainloop_lock(mainloop);
260
261
            if ((o = pa_stream_drain(stream, success_cb, NULL))) {
262
263
                while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
264
                    CHECK_DEAD_GOTO(fail);
265
                    pa_threaded_mainloop_wait(mainloop);
266
                }
267
268
            fail:
269
                
270
                pa_operation_unref(o);
271
            }
272
273
        pa_threaded_mainloop_unlock(mainloop);
274
        }
275
    }
276
277
    if (mainloop)
278
        pa_threaded_mainloop_stop(mainloop);
279
    
280
    if (stream) {
281
        pa_stream_disconnect(stream);
282
        pa_stream_unref(stream);
283
        stream = NULL;
284
    }
285
286
    if (context) {
287
        pa_context_disconnect(context);
288
        pa_context_unref(context);
289
        context = NULL;
290
    }
291
292
    if (mainloop) {
293
        pa_threaded_mainloop_free(mainloop);
294
        mainloop = NULL;
295
    }
296
}
297
298
/** Play the specified data to the pulseaudio server */
299
static int play(void* data, int len, int flags) {
300
    int r = -1;
301
    pa_operation *o = NULL;
302
    
303
    assert(stream);
304
    assert(context);
305
306
#ifdef PULSE_DEBUG
307
    fprintf(stderr, "playing %lu ***\n", len); 
308
#endif
309
    
310
    pa_threaded_mainloop_lock(mainloop);
311
312
    CHECK_DEAD_GOTO(fail);
313
314
    if (len) {
315
316
        if (pa_stream_write(stream, data, len, NULL, 0, PA_SEEK_RELATIVE) < 0) {
317
            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_write() failed: %s\n", pa_strerror(pa_context_errno(context)));
318
            goto fail;
319
        }
320
        
321
    } else {
322
323
        if (!(o = pa_stream_trigger(stream, NULL, NULL))) {
324
            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_trigger() failed: %s\n", pa_strerror(pa_context_errno(context)));
325
            goto fail;
326
        }
327
328
        /* We don't wait for this operation to complete */
329
    }
330
331
    r = len;
332
    
333
fail:
334
    if (o)
335
        pa_operation_unref(o);
336
337
    pa_threaded_mainloop_unlock(mainloop);
338
    
339
    return r;
340
}
341
342
static void cork(int b) {
343
    pa_operation *o = NULL;
344
    int success = 0;
345
    
346
    assert(stream);
347
    assert(context);
348
349
#ifdef PULSE_DEBUG
350
    fprintf(stderr, "cork(%i) ***\n", b); 
351
#endif
352
    
353
    pa_threaded_mainloop_lock(mainloop);
354
355
    CHECK_DEAD_GOTO(fail);
356
    
357
    if (!(o = pa_stream_cork(stream, b, success_cb, &success))) {
358
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_cork() failed: %s\n", pa_strerror(pa_context_errno(context)));
359
        goto fail;
360
    }
361
    
362
    while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
363
        CHECK_DEAD_GOTO(fail);
364
        pa_threaded_mainloop_wait(mainloop);
365
    }
366
367
    if (!success) 
368
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_cork() failed: %s\n", pa_strerror(pa_context_errno(context)));
369
    
370
    pa_operation_unref(o);
371
372
fail:
373
    pa_threaded_mainloop_unlock(mainloop);
374
}
375
376
/** Pause the audio stream by corking it on the server */
377
static void audio_pause(void) {
378
    cork(1);
379
 }
380
381
/** Resume the audio stream by uncorking it on the server */
382
static void audio_resume(void) {
383
    cork(0);
384
}
385
386
/** Reset the audio stream, i.e. flush the playback buffer on the server side */
387
static void reset(void) {
388
    pa_operation *o = NULL;
389
    int success = 0;
390
    
391
    assert(stream);
392
    assert(context);
393
394
#ifdef PULSE_DEBUG
395
    fprintf(stderr, "reset() ***\n"); 
396
#endif
397
    
398
    pa_threaded_mainloop_lock(mainloop);
399
400
    CHECK_DEAD_GOTO(fail);
401
    
402
    if (!(o = pa_stream_flush(stream, success_cb, &success))) {
403
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_flush() failed: %s\n", pa_strerror(pa_context_errno(context)));
404
        goto fail;
405
    }
406
    
407
    while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
408
        CHECK_DEAD_GOTO(fail);
409
        pa_threaded_mainloop_wait(mainloop);
410
    }
411
412
    if (!success) 
413
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_flush() failed: %s\n", pa_strerror(pa_context_errno(context)));
414
    
415
    pa_operation_unref(o);
416
417
fail:
418
    pa_threaded_mainloop_unlock(mainloop);
419
}
420
421
/** Return number of bytes that may be written to the server without blocking */
422
static int get_space(void) {
423
    size_t l = (size_t) -1;
424
425
    pa_threaded_mainloop_lock(mainloop);
426
427
    CHECK_DEAD_GOTO(fail);
428
429
    l = pa_stream_writable_size(stream);
430
431
#ifdef PULSE_DEBUG
432
    fprintf(stderr, "\nspace = %lu\n", l); 
433
#endif
434
435
fail:
436
    
437
    pa_threaded_mainloop_unlock(mainloop);
438
439
    return l == (size_t) -1 ? -1 : (int) l;
440
}
441
442
/** Return the current latency in seconds */
443
static float get_delay(void) {
444
    pa_usec_t latency = (pa_usec_t) -1;
445
446
    pa_threaded_mainloop_lock(mainloop);
447
448
    for (;;) {
449
        CHECK_DEAD_GOTO(fail);
450
451
        if (pa_stream_get_latency(stream, &latency, NULL) >= 0)
452
            break;
453
454
        if (pa_context_errno(context) != PA_ERR_NODATA) {
455
            mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_get_latency() failed: %s\n", pa_strerror(pa_context_errno(context)));
456
            goto fail;
457
        }
458
        
459
        /* Wait until latency data is available again */
460
        pa_threaded_mainloop_wait(mainloop);
461
    }
462
463
#ifdef PULSE_DEBUG
464
    fprintf(stderr, "latency=%0.3f sec\n", (double) latency / 1000000); 
465
#endif
466
467
fail:
468
    pa_threaded_mainloop_unlock(mainloop);
469
470
    return (latency == (pa_usec_t) -1) ? 0 : ((float) latency / 1000000.0);
471
}
472
473
/** A callback function that is called when the
474
 * pa_context_get_sink_input_info() operation completes. Saves the
475
 * volume field of the specified structure to the global variable volume. */
476
static void info_func(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) {
477
    if (is_last < 0) {
478
        mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to get sink input info: %s\n", pa_strerror(pa_context_errno(context)));
479
        return;
480
    }
481
482
    if (!i)
483
        return;
484
485
    volume = i->volume;
486
    volume_initialized = 1;
487
    
488
    pa_threaded_mainloop_signal(mainloop, 0);
489
}
490
491
/** Issue special libao controls on the device */
492
static int control(int cmd, void *arg) {
493
    
494
    if (!context || !stream)
495
        return CONTROL_ERROR;
496
    
497
    switch (cmd) {
498
        
499
        case AOCONTROL_GET_VOLUME: {
500
            /* Return the current volume of the playback stream */
501
            ao_control_vol_t *vol = (ao_control_vol_t*) arg;
502
            pa_operation *o;
503
504
            if (!(o = pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_func, NULL))) {
505
                mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_get_sink_input_info() failed: %s\n", pa_strerror(pa_context_errno(context)));
506
                return CONTROL_ERROR;
507
            }
508
    
509
            while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
510
                CHECK_DEAD_GOTO(fail);
511
                pa_threaded_mainloop_wait(mainloop);
512
            }
513
514
        fail:
515
            pa_operation_unref(o);
516
517
            if (!volume_initialized) {
518
                mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_stream_get_sink_input_info() failed: %s\n", pa_strerror(pa_context_errno(context)));
519
                return CONTROL_ERROR;
520
            }
521
            
522
            if (volume.channels != 2)
523
                vol->left = vol->right = (int) ((pa_cvolume_avg(&volume)*100)/PA_VOLUME_NORM);
524
            else {
525
                vol->left = (int) (volume.values[0]*100)/PA_VOLUME_NORM;
526
                vol->right = (int) (volume.values[1]*100)/PA_VOLUME_NORM;
527
            }
528
                
529
            return CONTROL_OK;
530
        }
531
            
532
        case AOCONTROL_SET_VOLUME: {
533
            /* Set the playback volume of the stream */
534
            const ao_control_vol_t *vol = (ao_control_vol_t*) arg;
535
            pa_operation *o;
536
537
            if (!volume_initialized) {
538
                pa_cvolume_reset(&volume, 2);
539
                volume_initialized = 1;
540
            }
541
            
542
            if (volume.channels != 2)
543
                pa_cvolume_set(&volume, volume.channels, ((pa_volume_t) vol->left*PA_VOLUME_NORM)/100);
544
            else {
545
                volume.values[0] = ((pa_volume_t) vol->left*PA_VOLUME_NORM)/100;
546
                volume.values[1] = ((pa_volume_t) vol->right*PA_VOLUME_NORM)/100;
547
            }
548
549
            if (!(o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL))) {
550
                mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] pa_context_set_sink_input_volume() failed: %s\n", pa_strerror(pa_context_errno(context)));
551
                return CONTROL_ERROR;
552
            }
553
554
            pa_operation_unref(o);
555
556
            /* We don't wait for completion here */
557
            
558
            return CONTROL_OK;
559
        }
560
            
561
        default:
562
            /* Unknown CONTROL command */
563
            return CONTROL_UNKNOWN;
564
    }
565
}
(-)mplayer-20070427.orig/libao2/audio_out.c (-4 / +4 lines)
Lines 25-32 Link Here
25
#ifdef USE_ESD
25
#ifdef USE_ESD
26
extern ao_functions_t audio_out_esd;
26
extern ao_functions_t audio_out_esd;
27
#endif
27
#endif
28
#ifdef USE_POLYP
28
#ifdef USE_PULSE
29
extern ao_functions_t audio_out_polyp;
29
extern ao_functions_t audio_out_pulse;
30
#endif
30
#endif
31
#ifdef USE_JACK
31
#ifdef USE_JACK
32
extern ao_functions_t audio_out_jack;
32
extern ao_functions_t audio_out_jack;
Lines 109-116 Link Here
109
#ifdef USE_ESD
109
#ifdef USE_ESD
110
        &audio_out_esd,
110
        &audio_out_esd,
111
#endif
111
#endif
112
#ifdef USE_POLYP
112
#ifdef USE_PULSE
113
        &audio_out_polyp,
113
        &audio_out_pulse,
114
#endif
114
#endif
115
#ifdef USE_JACK
115
#ifdef USE_JACK
116
        &audio_out_jack,
116
        &audio_out_jack,

Return to bug 183230