PerfectSetup: pulseaudio-patch.patch

File pulseaudio-patch.patch, 29.4 KB (added by ichbinanon, 5 years ago)
  • AUTHORS

     
    635635    * Darwin VCD/SVCD support 
    636636 
    637637Poettering, Lennart <mzzcynlre@0pointer.de> 
    638     * audio driver for the Polypaudio sound server 
     638    * audio driver for the PulseAudio sound server 
    639639 
    640640Poirier, Guillaume (poirierg) <poirierg@gmail.com> 
    641641    * French documentation translation and synchronization 
  • libao2/ao_pulse.c

     
     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 */ 
     18static ao_info_t info = { 
     19    "PulseAudio audio output", 
     20    "pulse", 
     21    "Lennart Poettering", 
     22    "" 
     23}; 
     24 
     25/** The sink to connect to */ 
     26static char *sink = NULL; 
     27 
     28/** PulseAudio playback stream object */ 
     29static struct pa_stream *stream = NULL; 
     30 
     31/** PulseAudio connection context */ 
     32static struct pa_context *context = NULL; 
     33 
     34/** Main event loop object */ 
     35static struct pa_threaded_mainloop *mainloop = NULL; 
     36 
     37/** A temporary variable to store the current volume */ 
     38static pa_cvolume volume; 
     39static int volume_initialized = 0; 
     40 
     41/** Some special libao macro magic */ 
     42LIBAO_EXTERN(pulse) 
     43 
     44#define CHECK_DEAD_GOTO(label) do { \ 
     45if (!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 
     52static 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 
     70static 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 
     87static 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 
     93static void stream_latency_update_cb(pa_stream *s, void *userdata) { 
     94    assert(s); 
     95     
     96    pa_threaded_mainloop_signal(mainloop, 0); 
     97} 
     98 
     99static 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 */ 
     109static 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 
     238unlock_and_fail: 
     239 
     240    if (mainloop) 
     241        pa_threaded_mainloop_unlock(mainloop); 
     242     
     243fail: 
     244     
     245    uninit(1); 
     246    return 0; 
     247} 
     248 
     249/** Destroy libao driver */ 
     250static 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 */ 
     299static 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     
     333fail: 
     334    if (o) 
     335        pa_operation_unref(o); 
     336 
     337    pa_threaded_mainloop_unlock(mainloop); 
     338     
     339    return r; 
     340} 
     341 
     342static 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 
     372fail: 
     373    pa_threaded_mainloop_unlock(mainloop); 
     374} 
     375 
     376/** Pause the audio stream by corking it on the server */ 
     377static void audio_pause(void) { 
     378    cork(1); 
     379 } 
     380 
     381/** Resume the audio stream by uncorking it on the server */ 
     382static void audio_resume(void) { 
     383    cork(0); 
     384} 
     385 
     386/** Reset the audio stream, i.e. flush the playback buffer on the server side */ 
     387static 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 
     417fail: 
     418    pa_threaded_mainloop_unlock(mainloop); 
     419} 
     420 
     421/** Return number of bytes that may be written to the server without blocking */ 
     422static 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 
     435fail: 
     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 */ 
     443static 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 
     467fail: 
     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. */ 
     476static 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 */ 
     492static 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} 
     566 
     567 
  • libao2/ao_polyp.c

     
    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  
  • libao2/audio_out.c

     
    2525#ifdef USE_ESD 
    2626extern ao_functions_t audio_out_esd; 
    2727#endif 
    28 #ifdef USE_POLYP 
    29 extern ao_functions_t audio_out_polyp; 
     28#ifdef USE_PULSE 
     29extern ao_functions_t audio_out_pulse; 
    3030#endif 
    3131#ifdef USE_JACK 
    3232extern ao_functions_t audio_out_jack; 
     
    112112#ifdef USE_ESD 
    113113        &audio_out_esd, 
    114114#endif 
    115 #ifdef USE_POLYP 
    116         &audio_out_polyp, 
     115#ifdef USE_PULSE 
     116        &audio_out_pulse, 
    117117#endif 
    118118#ifdef USE_JACK 
    119119        &audio_out_jack, 
  • configure

     
    390390  --disable-ossaudio     disable OSS audio output [autodetect] 
    391391  --disable-arts         disable aRts audio output [autodetect] 
    392392  --disable-esd          disable esd audio output [autodetect] 
    393   --disable-polyp        disable Polypaudio audio output [autodetect] 
     393  --disable-pulse        disable Pulseaudio audio output [autodetect] 
    394394  --disable-jack         disable JACK audio output [autodetect] 
    395395  --disable-openal       disable OpenAL audio output [autodetect] 
    396396  --disable-nas          disable NAS audio output [autodetect] 
     
    555555_ossaudio=auto 
    556556_arts=auto 
    557557_esd=auto 
    558 _polyp=auto 
     558_pulse=auto 
    559559_jack=auto 
    560560_openal=auto 
    561561_libcdio=auto 
     
    880880  --disable-arts)   _arts=no    ;; 
    881881  --enable-esd)     _esd=yes    ;; 
    882882  --disable-esd)    _esd=no     ;; 
    883   --enable-polyp)   _polyp=yes  ;; 
    884   --disable-polyp)  _polyp=no       ;; 
     883  --enable-pulse)   _pulse=yes  ;; 
     884  --disable-pulse)  _pulse=no       ;; 
    885885  --enable-jack)    _jack=yes   ;; 
    886886  --disable-jack)   _jack=no    ;; 
    887887  --enable-openal)  _openal=yes ;; 
     
    50755075  _noaomodules="esd $_noaomodules" 
    50765076fi 
    50775077 
    5078 echocheck "Polyp" 
    5079 if test "$_polyp" = auto ; then 
    5080   _polyp=no 
    5081   if $_pkg_config --exists 'polyplib >= 0.6 polyplib-error >= 0.6 polyplib-mainloop >= 0.6' ; then 
     5078echocheck "pulse" 
     5079if test "$_pulse" = auto ; then 
     5080  _pulse=no 
     5081  if $_pkg_config --exists 'libpulse >= 0.9' ; then 
    50825082 
    50835083cat > $TMPC << EOF 
    5084 #include <polyp/polyplib.h> 
    5085 #include <polyp/mainloop.h> 
    5086 #include <polyp/polyplib-error.h> 
     5084#include <pulse/pulseaudio.h> 
    50875085int main(void) { return 0; } 
    50885086EOF 
    5089 cc_check `$_pkg_config --libs --cflags polyplib polyplib-error polyplib-mainloop` && tmp_run && _polyp=yes 
     5087cc_check `$_pkg_config --libs --cflags libpulse` && tmp_run && _pulse=yes 
    50905088 
    50915089  fi 
    50925090fi 
    5093 echores "$_polyp" 
     5091echores "$_pulse" 
    50945092 
    5095 if test "$_polyp" = yes ; then 
    5096   _def_polyp='#define USE_POLYP 1' 
    5097   _aosrc="$_aosrc ao_polyp.c" 
    5098   _aomodules="polyp $_aomodules" 
    5099   _libs_mplayer="$_libs_mplayer `$_pkg_config --libs polyplib polyplib-error polyplib-mainloop`" 
    5100   _inc_extra="$_inc_extra `$_pkg_config --cflags polyplib polyplib-error polyplib-mainloop`" 
     5093if test "$_pulse" = yes ; then 
     5094  _def_pulse='#define USE_PULSE 1' 
     5095  _aosrc="$_aosrc ao_pulse.c" 
     5096  _aomodules="pulse $_aomodules" 
     5097  _libs_mplayer="$_libs_mplayer `$_pkg_config --libs libpulse`" 
     5098  _inc_extra="$_inc_extra `$_pkg_config --cflags libpulse`" 
    51015099else 
    5102   _def_polyp='#undef USE_POLYP' 
    5103   _noaomodules="polyp $_noaomodules" 
     5100  _def_pulse='#undef USE_PULSE' 
     5101  _noaomodules="pulse $_noaomodules" 
    51045102fi 
    51055103 
    51065104 
     
    80988096$_def_arts 
    80998097$_def_esd 
    81008098$_def_esd_latency 
    8101 $_def_polyp 
     8099$_def_pulse 
    81028100$_def_jack 
    81038101$_def_openal 
    81048102$_def_openal_h