~ubuntu-branches/ubuntu/trusty/mplayer2/trusty-proposed

« back to all changes in this revision

Viewing changes to libao2/ao_esd.c

  • Committer: Package Import Robot
  • Author(s): Alessio Treglia
  • Date: 2012-05-19 20:07:25 UTC
  • mfrom: (5.1.11 sid)
  • Revision ID: package-import@ubuntu.com-20120519200725-u66fkxis0pcw094k
* New upstream snapshot:
  - Pass a dummy address instead of NULL pointer as third argument to
    FcFontMatch() to fix an assertion failure with the latest 2.9.0
    version of fontconfig (Closes: #672947).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * EsounD audio output driver for MPlayer
3
 
 *
4
 
 * copyright (c) 2002 Juergen Keil <jk@tools.de>
5
 
 *
6
 
 * This file is part of MPlayer.
7
 
 *
8
 
 * MPlayer is free software; you can redistribute it and/or modify
9
 
 * it under the terms of the GNU General Public License as published by
10
 
 * the Free Software Foundation; either version 2 of the License, or
11
 
 * (at your option) any later version.
12
 
 *
13
 
 * MPlayer is distributed in the hope that it will be useful,
14
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
 * GNU General Public License for more details.
17
 
 *
18
 
 * You should have received a copy of the GNU General Public License along
19
 
 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20
 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 
 */
22
 
 
23
 
 /*
24
 
 * TODO / known problems:
25
 
 * - does not work well when the esd daemon has autostandby disabled
26
 
 *   (workaround: run esd with option "-as 2" - fortunatelly this is
27
 
 *    the default)
28
 
 * - plays noise on a linux 2.4.4 kernel with a SB16PCI card, when using
29
 
 *   a local tcp connection to the esd daemon; there is no noise when using
30
 
 *   a unix domain socket connection.
31
 
 *   (there are EIO errors reported by the sound card driver, so this is
32
 
 *   most likely a linux sound card driver problem)
33
 
 */
34
 
 
35
 
#include <sys/types.h>
36
 
#include <sys/time.h>
37
 
#include <sys/socket.h>
38
 
#include <stdio.h>
39
 
#include <string.h>
40
 
#include <unistd.h>
41
 
#include <errno.h>
42
 
#include <fcntl.h>
43
 
#include <time.h>
44
 
#ifdef  __svr4__
45
 
#include <stropts.h>
46
 
#endif
47
 
#include <esd.h>
48
 
 
49
 
#include "config.h"
50
 
#include "audio_out.h"
51
 
#include "audio_out_internal.h"
52
 
#include "libaf/af_format.h"
53
 
#include "mp_msg.h"
54
 
 
55
 
 
56
 
#define ESD_RESAMPLES 0
57
 
#define ESD_DEBUG 0
58
 
 
59
 
#if     ESD_DEBUG
60
 
#define dprintf(...)    printf(__VA_ARGS__)
61
 
#else
62
 
#define dprintf(...)    /**/
63
 
#endif
64
 
 
65
 
 
66
 
#define ESD_CLIENT_NAME "MPlayer"
67
 
#define ESD_MAX_DELAY   (1.0f)  /* max amount of data buffered in esd (#sec) */
68
 
 
69
 
static const ao_info_t info =
70
 
{
71
 
    "EsounD audio output",
72
 
    "esd",
73
 
    "Juergen Keil <jk@tools.de>",
74
 
    ""
75
 
};
76
 
 
77
 
LIBAO_EXTERN(esd)
78
 
 
79
 
static int esd_fd = -1;
80
 
static int esd_play_fd = -1;
81
 
static esd_server_info_t *esd_svinfo;
82
 
static int esd_latency;
83
 
static int esd_bytes_per_sample;
84
 
static unsigned long esd_samples_written;
85
 
static struct timeval esd_play_start;
86
 
extern float audio_delay;
87
 
 
88
 
/*
89
 
 * to set/get/query special features/parameters
90
 
 */
91
 
static int control(int cmd, void *arg)
92
 
{
93
 
    esd_player_info_t *esd_pi;
94
 
    esd_info_t        *esd_i;
95
 
    time_t             now;
96
 
    static time_t      vol_cache_time;
97
 
    static ao_control_vol_t vol_cache;
98
 
 
99
 
    switch (cmd) {
100
 
    case AOCONTROL_GET_VOLUME:
101
 
        time(&now);
102
 
        if (now == vol_cache_time) {
103
 
            *(ao_control_vol_t *)arg = vol_cache;
104
 
            return CONTROL_OK;
105
 
        }
106
 
 
107
 
        dprintf("esd: get vol\n");
108
 
        if ((esd_i = esd_get_all_info(esd_fd)) == NULL)
109
 
            return CONTROL_ERROR;
110
 
 
111
 
        for (esd_pi = esd_i->player_list; esd_pi != NULL; esd_pi = esd_pi->next)
112
 
            if (strcmp(esd_pi->name, ESD_CLIENT_NAME) == 0)
113
 
                break;
114
 
 
115
 
        if (esd_pi != NULL) {
116
 
            ao_control_vol_t *vol = (ao_control_vol_t *)arg;
117
 
            vol->left =  esd_pi->left_vol_scale  * 100 / ESD_VOLUME_BASE;
118
 
            vol->right = esd_pi->right_vol_scale * 100 / ESD_VOLUME_BASE;
119
 
 
120
 
            vol_cache = *vol;
121
 
            vol_cache_time = now;
122
 
        }
123
 
        esd_free_all_info(esd_i);
124
 
 
125
 
        return CONTROL_OK;
126
 
 
127
 
    case AOCONTROL_SET_VOLUME:
128
 
        dprintf("esd: set vol\n");
129
 
        if ((esd_i = esd_get_all_info(esd_fd)) == NULL)
130
 
            return CONTROL_ERROR;
131
 
 
132
 
        for (esd_pi = esd_i->player_list; esd_pi != NULL; esd_pi = esd_pi->next)
133
 
            if (strcmp(esd_pi->name, ESD_CLIENT_NAME) == 0)
134
 
                break;
135
 
 
136
 
        if (esd_pi != NULL) {
137
 
            ao_control_vol_t *vol = (ao_control_vol_t *)arg;
138
 
            esd_set_stream_pan(esd_fd, esd_pi->source_id,
139
 
                               vol->left  * ESD_VOLUME_BASE / 100,
140
 
                               vol->right * ESD_VOLUME_BASE / 100);
141
 
 
142
 
            vol_cache = *vol;
143
 
            time(&vol_cache_time);
144
 
        }
145
 
        esd_free_all_info(esd_i);
146
 
        return CONTROL_OK;
147
 
 
148
 
    default:
149
 
        return CONTROL_UNKNOWN;
150
 
    }
151
 
}
152
 
 
153
 
 
154
 
/*
155
 
 * open & setup audio device
156
 
 * return: 1=success 0=fail
157
 
 */
158
 
static int init(int rate_hz, int channels, int format, int flags)
159
 
{
160
 
    esd_format_t esd_fmt;
161
 
    int bytes_per_sample;
162
 
    int fl;
163
 
    char *server = ao_subdevice;  /* NULL for localhost */
164
 
    float lag_seconds, lag_net = 0., lag_serv;
165
 
    struct timeval proto_start, proto_end;
166
 
 
167
 
    global_ao->no_persistent_volume = true;
168
 
 
169
 
    if (esd_fd < 0) {
170
 
        esd_fd = esd_open_sound(server);
171
 
        if (esd_fd < 0) {
172
 
            mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ESD] esd_open_sound failed: %s\n",
173
 
                   strerror(errno));
174
 
            return 0;
175
 
        }
176
 
 
177
 
        /* get server info, and measure network latency */
178
 
        gettimeofday(&proto_start, NULL);
179
 
        esd_svinfo = esd_get_server_info(esd_fd);
180
 
        if(server) {
181
 
            gettimeofday(&proto_end, NULL);
182
 
            lag_net  = (proto_end.tv_sec  - proto_start.tv_sec) +
183
 
                (proto_end.tv_usec - proto_start.tv_usec) / 1000000.0;
184
 
            lag_net /= 2.0; /* round trip -> one way */
185
 
        } else
186
 
            lag_net = 0.0;  /* no network lag */
187
 
 
188
 
        /*
189
 
        if (esd_svinfo) {
190
 
            mp_msg(MSGT_AO, MSGL_INFO, "AO: [esd] server info:\n");
191
 
            esd_print_server_info(esd_svinfo);
192
 
        }
193
 
        */
194
 
    }
195
 
 
196
 
    esd_fmt = ESD_STREAM | ESD_PLAY;
197
 
 
198
 
#if     ESD_RESAMPLES
199
 
    /* let the esd daemon convert sample rate */
200
 
#else
201
 
    /* let mplayer's audio filter convert the sample rate */
202
 
    if (esd_svinfo != NULL)
203
 
        rate_hz = esd_svinfo->rate;
204
 
#endif
205
 
    ao_data.samplerate = rate_hz;
206
 
 
207
 
    /* EsounD can play mono or stereo */
208
 
    switch (channels) {
209
 
    case 1:
210
 
        esd_fmt |= ESD_MONO;
211
 
        ao_data.channels = bytes_per_sample = 1;
212
 
        break;
213
 
    default:
214
 
        esd_fmt |= ESD_STEREO;
215
 
        ao_data.channels = bytes_per_sample = 2;
216
 
        break;
217
 
    }
218
 
 
219
 
    /* EsounD can play 8bit unsigned and 16bit signed native */
220
 
    switch (format) {
221
 
    case AF_FORMAT_S8:
222
 
    case AF_FORMAT_U8:
223
 
        esd_fmt |= ESD_BITS8;
224
 
        ao_data.format = AF_FORMAT_U8;
225
 
        break;
226
 
    default:
227
 
        esd_fmt |= ESD_BITS16;
228
 
        ao_data.format = AF_FORMAT_S16_NE;
229
 
        bytes_per_sample *= 2;
230
 
        break;
231
 
    }
232
 
 
233
 
    /* modify audio_delay depending on esd_latency
234
 
     * latency is number of samples @ 44.1khz stereo 16 bit
235
 
     * adjust according to rate_hz & bytes_per_sample
236
 
     */
237
 
#ifdef CONFIG_ESD_LATENCY
238
 
    esd_latency = esd_get_latency(esd_fd);
239
 
#else
240
 
    esd_latency = ((channels == 1 ? 2 : 1) * ESD_DEFAULT_RATE *
241
 
                   (ESD_BUF_SIZE + 64 * (4.0f / bytes_per_sample))
242
 
                   ) / rate_hz;
243
 
    esd_latency += ESD_BUF_SIZE * 2;
244
 
#endif
245
 
    if(esd_latency > 0) {
246
 
        lag_serv = (esd_latency * 4.0f) / (bytes_per_sample * rate_hz);
247
 
        lag_seconds = lag_net + lag_serv;
248
 
        audio_delay += lag_seconds;
249
 
        mp_tmsg(MSGT_AO, MSGL_INFO,"[AO ESD] latency: [server: %0.2fs, net: %0.2fs] (adjust %0.2fs)\n",
250
 
               lag_serv, lag_net, lag_seconds);
251
 
    }
252
 
 
253
 
    esd_play_fd = esd_play_stream_fallback(esd_fmt, rate_hz,
254
 
                                           server, ESD_CLIENT_NAME);
255
 
    if (esd_play_fd < 0) {
256
 
        mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ESD] failed to open ESD playback stream: %s\n", strerror(errno));
257
 
        return 0;
258
 
    }
259
 
 
260
 
    /* enable non-blocking i/o on the socket connection to the esd server */
261
 
    if ((fl = fcntl(esd_play_fd, F_GETFL)) >= 0)
262
 
        fcntl(esd_play_fd, F_SETFL, O_NDELAY|fl);
263
 
 
264
 
#if ESD_DEBUG
265
 
    {
266
 
        int sbuf, rbuf, len;
267
 
        len = sizeof(sbuf);
268
 
        getsockopt(esd_play_fd, SOL_SOCKET, SO_SNDBUF, &sbuf, &len);
269
 
        len = sizeof(rbuf);
270
 
        getsockopt(esd_play_fd, SOL_SOCKET, SO_RCVBUF, &rbuf, &len);
271
 
        dprintf("esd: send/receive socket buffer space %d/%d bytes\n",
272
 
                sbuf, rbuf);
273
 
    }
274
 
#endif
275
 
 
276
 
    ao_data.bps = bytes_per_sample * rate_hz;
277
 
    ao_data.outburst = ao_data.bps > 100000 ? 4*ESD_BUF_SIZE : 2*ESD_BUF_SIZE;
278
 
 
279
 
    esd_play_start.tv_sec = 0;
280
 
    esd_samples_written = 0;
281
 
    esd_bytes_per_sample = bytes_per_sample;
282
 
 
283
 
    return 1;
284
 
}
285
 
 
286
 
 
287
 
/*
288
 
 * close audio device
289
 
 */
290
 
static void uninit(int immed)
291
 
{
292
 
    if (esd_play_fd >= 0) {
293
 
        esd_close(esd_play_fd);
294
 
        esd_play_fd = -1;
295
 
    }
296
 
 
297
 
    if (esd_svinfo) {
298
 
        esd_free_server_info(esd_svinfo);
299
 
        esd_svinfo = NULL;
300
 
    }
301
 
 
302
 
    if (esd_fd >= 0) {
303
 
        esd_close(esd_fd);
304
 
        esd_fd = -1;
305
 
    }
306
 
}
307
 
 
308
 
 
309
 
/*
310
 
 * plays 'len' bytes of 'data'
311
 
 * it should round it down to outburst*n
312
 
 * return: number of bytes played
313
 
 */
314
 
static int play(void* data, int len, int flags)
315
 
{
316
 
    int offs;
317
 
    int nwritten;
318
 
    int nsamples;
319
 
    int n;
320
 
 
321
 
    /* round down buffersize to a multiple of ESD_BUF_SIZE bytes */
322
 
    len = len / ESD_BUF_SIZE * ESD_BUF_SIZE;
323
 
    if (len <= 0)
324
 
        return 0;
325
 
 
326
 
#define SINGLE_WRITE 0
327
 
#if     SINGLE_WRITE
328
 
    nwritten = write(esd_play_fd, data, len);
329
 
#else
330
 
    for (offs = 0, nwritten=0; offs + ESD_BUF_SIZE <= len; offs += ESD_BUF_SIZE) {
331
 
        /*
332
 
         * note: we're writing to a non-blocking socket here.
333
 
         * A partial write means, that the socket buffer is full.
334
 
         */
335
 
        n = write(esd_play_fd, (char*)data + offs, ESD_BUF_SIZE);
336
 
        if ( n < 0 ) {
337
 
            if ( errno != EAGAIN )
338
 
                dprintf("esd play: write failed: %s\n", strerror(errno));
339
 
            break;
340
 
        } else if ( n != ESD_BUF_SIZE ) {
341
 
            nwritten += n;
342
 
            break;
343
 
        } else
344
 
            nwritten += n;
345
 
    }
346
 
#endif
347
 
 
348
 
    if (nwritten > 0) {
349
 
        if (!esd_play_start.tv_sec)
350
 
            gettimeofday(&esd_play_start, NULL);
351
 
        nsamples = nwritten / esd_bytes_per_sample;
352
 
        esd_samples_written += nsamples;
353
 
 
354
 
        dprintf("esd play: %d %lu\n", nsamples, esd_samples_written);
355
 
    } else {
356
 
        dprintf("esd play: blocked / %lu\n", esd_samples_written);
357
 
    }
358
 
 
359
 
    return nwritten;
360
 
}
361
 
 
362
 
 
363
 
/*
364
 
 * stop playing, keep buffers (for pause)
365
 
 */
366
 
static void audio_pause(void)
367
 
{
368
 
    /*
369
 
     * not possible with esd.  the esd daemom will continue playing
370
 
     * buffered data (not more than ESD_MAX_DELAY seconds of samples)
371
 
     */
372
 
}
373
 
 
374
 
 
375
 
/*
376
 
 * resume playing, after audio_pause()
377
 
 */
378
 
static void audio_resume(void)
379
 
{
380
 
    /*
381
 
     * not possible with esd.
382
 
     *
383
 
     * Let's hope the pause was long enough that the esd ran out of
384
 
     * buffered data;  we restart our time based delay computation
385
 
     * for an audio resume.
386
 
     */
387
 
    esd_play_start.tv_sec = 0;
388
 
    esd_samples_written = 0;
389
 
}
390
 
 
391
 
 
392
 
/*
393
 
 * stop playing and empty buffers (for seeking/pause)
394
 
 */
395
 
static void reset(void)
396
 
{
397
 
#ifdef  __svr4__
398
 
    /* throw away data buffered in the esd connection */
399
 
    if (ioctl(esd_play_fd, I_FLUSH, FLUSHW))
400
 
        perror("I_FLUSH");
401
 
#endif
402
 
}
403
 
 
404
 
 
405
 
/*
406
 
 * return: how many bytes can be played without blocking
407
 
 */
408
 
static int get_space(void)
409
 
{
410
 
    struct timeval tmout;
411
 
    fd_set wfds;
412
 
    float current_delay;
413
 
    int space;
414
 
 
415
 
    /*
416
 
     * Don't buffer too much data in the esd daemon.
417
 
     *
418
 
     * If we send too much, esd will block in write()s to the sound
419
 
     * device, and the consequence is a huge slow down for things like
420
 
     * esd_get_all_info().
421
 
     */
422
 
    if ((current_delay = get_delay()) >= ESD_MAX_DELAY) {
423
 
        dprintf("esd get_space: too much data buffered\n");
424
 
        return 0;
425
 
    }
426
 
 
427
 
    FD_ZERO(&wfds);
428
 
    FD_SET(esd_play_fd, &wfds);
429
 
    tmout.tv_sec = 0;
430
 
    tmout.tv_usec = 0;
431
 
 
432
 
    if (select(esd_play_fd + 1, NULL, &wfds, NULL, &tmout) != 1)
433
 
        return 0;
434
 
 
435
 
    if (!FD_ISSET(esd_play_fd, &wfds))
436
 
        return 0;
437
 
 
438
 
    /* try to fill 50% of the remaining "free" buffer space */
439
 
    space = (ESD_MAX_DELAY - current_delay) * ao_data.bps * 0.5f;
440
 
 
441
 
    /* round up to next multiple of ESD_BUF_SIZE */
442
 
    space = (space + ESD_BUF_SIZE-1) / ESD_BUF_SIZE * ESD_BUF_SIZE;
443
 
 
444
 
    dprintf("esd get_space: %d\n", space);
445
 
    return space;
446
 
}
447
 
 
448
 
 
449
 
/*
450
 
 * return: delay in seconds between first and last sample in buffer
451
 
 */
452
 
static float get_delay(void)
453
 
{
454
 
    struct timeval now;
455
 
    double buffered_samples_time;
456
 
    double play_time;
457
 
 
458
 
    if (!esd_play_start.tv_sec)
459
 
        return 0;
460
 
 
461
 
    buffered_samples_time = (float)esd_samples_written / ao_data.samplerate;
462
 
    gettimeofday(&now, NULL);
463
 
    play_time  =  now.tv_sec  - esd_play_start.tv_sec;
464
 
    play_time += (now.tv_usec - esd_play_start.tv_usec) / 1000000.;
465
 
 
466
 
    /* dprintf("esd delay: %f %f\n", play_time, buffered_samples_time); */
467
 
 
468
 
    if (play_time > buffered_samples_time) {
469
 
        dprintf("esd: underflow\n");
470
 
        esd_play_start.tv_sec = 0;
471
 
        esd_samples_written = 0;
472
 
        return 0;
473
 
    }
474
 
 
475
 
    dprintf("esd: get_delay %f\n", buffered_samples_time - play_time);
476
 
    return buffered_samples_time - play_time;
477
 
}