~diwic/ubuntu/lucid/pulseaudio/bugfixes

« back to all changes in this revision

Viewing changes to src/modules/module-null-sink.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2008-11-04 15:46:00 UTC
  • mfrom: (1.2.1 upstream) (1.1.6 lenny)
  • Revision ID: james.westby@ubuntu.com-20081104154600-hlzknpcazaam0nxm
Tags: 0.9.13-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Don't build against, and create jack package. Jack is not in main.
  - Remove --disable-per-user-esound-socket from configure flags, as we still
    want per user esound sockets.
  - Remove stop links from rc0 and rc6.
  - Change default resample algorithm and bubffer size.
  - Add alsa configuration files to route alsa applications via pulseaudio.
  - Move libasound2-plugins from Recommends to Depends.
* debian/pulseaudio.preinst: When upgrading from intrepid, remove
  /etc/X11/Xsession.d/70pulseaudio, as this was used to minimize a race
  condition when starting GNOME in intrepid. This race should not exist in
  jaunty once libcanberra is built to use pulseaudio as a backend.
* Do not spawn a pulseaudio server if clients fail to find a running server.
* Remove explicit version dependency for libspeex-dev to allow the package
  to be built for now.
* Regenerate autotools files to work with Ubuntu's newer libtool/libltdl.
* debian/control: libpulsecore5 -> libpulsecore8 to match the library
  soname.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: module-null-sink.c 2043 2007-11-09 18:25:40Z lennart $ */
2
 
 
3
1
/***
4
2
  This file is part of PulseAudio.
5
3
 
6
 
  Copyright 2004-2006 Lennart Poettering
 
4
  Copyright 2004-2008 Lennart Poettering
7
5
 
8
6
  PulseAudio is free software; you can redistribute it and/or modify
9
7
  it under the terms of the GNU Lesser General Public License as published
59
57
        "format=<sample format> "
60
58
        "channels=<number of channels> "
61
59
        "rate=<sample rate> "
62
 
        "sink_name=<name of sink>"
63
 
        "channel_map=<channel map>"
 
60
        "sink_name=<name of sink> "
 
61
        "channel_map=<channel map> "
64
62
        "description=<description for the sink>");
65
63
 
66
64
#define DEFAULT_SINK_NAME "null"
 
65
#define MAX_LATENCY_USEC (PA_USEC_PER_SEC * 2)
67
66
 
68
67
struct userdata {
69
68
    pa_core *core;
76
75
 
77
76
    size_t block_size;
78
77
 
79
 
    struct timeval timestamp;
 
78
    pa_usec_t block_usec;
 
79
    pa_usec_t timestamp;
80
80
};
81
81
 
82
82
static const char* const valid_modargs[] = {
96
96
        case PA_SINK_MESSAGE_SET_STATE:
97
97
 
98
98
            if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING)
99
 
                pa_rtclock_get(&u->timestamp);
 
99
                u->timestamp = pa_rtclock_usec();
100
100
 
101
101
            break;
102
102
 
103
103
        case PA_SINK_MESSAGE_GET_LATENCY: {
104
 
            struct timeval now;
105
 
 
106
 
            pa_rtclock_get(&now);
107
 
 
108
 
            if (pa_timeval_cmp(&u->timestamp, &now) > 0)
109
 
                *((pa_usec_t*) data) = 0;
110
 
            else
111
 
                *((pa_usec_t*) data) = pa_timeval_diff(&u->timestamp, &now);
112
 
            break;
 
104
            pa_usec_t now;
 
105
 
 
106
            now = pa_rtclock_usec();
 
107
            *((pa_usec_t*) data) = u->timestamp > now ? u->timestamp - now : 0;
 
108
 
 
109
            return 0;
113
110
        }
114
111
    }
115
112
 
116
113
    return pa_sink_process_msg(o, code, data, offset, chunk);
117
114
}
118
115
 
 
116
static void sink_update_requested_latency_cb(pa_sink *s) {
 
117
    struct userdata *u;
 
118
 
 
119
    pa_sink_assert_ref(s);
 
120
    u = s->userdata;
 
121
    pa_assert(u);
 
122
 
 
123
    u->block_usec = pa_sink_get_requested_latency_within_thread(s);
 
124
}
 
125
 
 
126
static void process_rewind(struct userdata *u, pa_usec_t now) {
 
127
    size_t rewind_nbytes, in_buffer;
 
128
    pa_usec_t delay;
 
129
 
 
130
    pa_assert(u);
 
131
 
 
132
    /* Figure out how much we shall rewind and reset the counter */
 
133
    rewind_nbytes = u->sink->thread_info.rewind_nbytes;
 
134
    u->sink->thread_info.rewind_nbytes = 0;
 
135
 
 
136
    pa_assert(rewind_nbytes > 0);
 
137
    pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes);
 
138
 
 
139
    if (u->timestamp <= now)
 
140
        goto do_nothing;
 
141
 
 
142
    delay = u->timestamp - now;
 
143
    in_buffer = pa_usec_to_bytes(delay, &u->sink->sample_spec);
 
144
 
 
145
    if (in_buffer <= 0)
 
146
        goto do_nothing;
 
147
 
 
148
    if (rewind_nbytes > in_buffer)
 
149
        rewind_nbytes = in_buffer;
 
150
 
 
151
    pa_sink_process_rewind(u->sink, rewind_nbytes);
 
152
    u->timestamp -= pa_bytes_to_usec(rewind_nbytes, &u->sink->sample_spec);
 
153
 
 
154
    pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes);
 
155
    return;
 
156
 
 
157
do_nothing:
 
158
 
 
159
    pa_sink_process_rewind(u->sink, 0);
 
160
}
 
161
 
 
162
static void process_render(struct userdata *u, pa_usec_t now) {
 
163
    size_t ate = 0;
 
164
 
 
165
    pa_assert(u);
 
166
 
 
167
    /* This is the configured latency. Sink inputs connected to us
 
168
    might not have a single frame more than the maxrequest value
 
169
    queed. Hence: at maximum read this many bytes from the sink
 
170
    inputs. */
 
171
 
 
172
    /* Fill the buffer up the the latency size */
 
173
    while (u->timestamp < now + u->block_usec) {
 
174
        pa_memchunk chunk;
 
175
 
 
176
        pa_sink_render(u->sink, u->sink->thread_info.max_request, &chunk);
 
177
        pa_memblock_unref(chunk.memblock);
 
178
 
 
179
/*         pa_log_debug("Ate %lu bytes.", (unsigned long) chunk.length); */
 
180
        u->timestamp += pa_bytes_to_usec(chunk.length, &u->sink->sample_spec);
 
181
 
 
182
        ate += chunk.length;
 
183
 
 
184
        if (ate >= u->sink->thread_info.max_request)
 
185
            break;
 
186
    }
 
187
 
 
188
/*     pa_log_debug("Ate in sum %lu bytes (of %lu)", (unsigned long) ate, (unsigned long) nbytes); */
 
189
}
 
190
 
119
191
static void thread_func(void *userdata) {
120
192
    struct userdata *u = userdata;
121
193
 
126
198
    pa_thread_mq_install(&u->thread_mq);
127
199
    pa_rtpoll_install(u->rtpoll);
128
200
 
129
 
    pa_rtclock_get(&u->timestamp);
 
201
    u->timestamp = pa_rtclock_usec();
130
202
 
131
203
    for (;;) {
132
204
        int ret;
133
205
 
134
206
        /* Render some data and drop it immediately */
135
 
        if (u->sink->thread_info.state == PA_SINK_RUNNING) {
136
 
            struct timeval now;
137
 
 
138
 
            pa_rtclock_get(&now);
139
 
 
140
 
            if (pa_timeval_cmp(&u->timestamp, &now) <= 0) {
141
 
                pa_sink_skip(u->sink, u->block_size);
142
 
                pa_timeval_add(&u->timestamp, pa_bytes_to_usec(u->block_size, &u->sink->sample_spec));
 
207
        if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
 
208
            pa_usec_t now;
 
209
 
 
210
            now = pa_rtclock_usec();
 
211
 
 
212
            if (u->sink->thread_info.rewind_requested) {
 
213
                if (u->sink->thread_info.rewind_nbytes > 0)
 
214
                    process_rewind(u, now);
 
215
                else
 
216
                    pa_sink_process_rewind(u->sink, 0);
143
217
            }
144
218
 
145
 
            pa_rtpoll_set_timer_absolute(u->rtpoll, &u->timestamp);
 
219
            if (u->timestamp <= now)
 
220
                process_render(u, now);
 
221
 
 
222
            pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp);
146
223
        } else
147
224
            pa_rtpoll_set_timer_disabled(u->rtpoll);
148
225
 
149
226
        /* Hmm, nothing to do. Let's sleep */
150
 
        if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0)
 
227
        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
151
228
            goto fail;
152
229
 
153
230
        if (ret == 0)
169
246
    pa_sample_spec ss;
170
247
    pa_channel_map map;
171
248
    pa_modargs *ma = NULL;
 
249
    pa_sink_new_data data;
172
250
 
173
251
    pa_assert(m);
174
252
 
183
261
        goto fail;
184
262
    }
185
263
 
186
 
    u = pa_xnew0(struct userdata, 1);
 
264
    m->userdata = u = pa_xnew0(struct userdata, 1);
187
265
    u->core = m->core;
188
266
    u->module = m;
189
 
    m->userdata = u;
190
 
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
191
267
    u->rtpoll = pa_rtpoll_new();
192
 
    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
193
 
 
194
 
    if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
195
 
        pa_log("Failed to create sink.");
 
268
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
 
269
 
 
270
    pa_sink_new_data_init(&data);
 
271
    data.driver = __FILE__;
 
272
    data.module = m;
 
273
    pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
 
274
    pa_sink_new_data_set_sample_spec(&data, &ss);
 
275
    pa_sink_new_data_set_channel_map(&data, &map);
 
276
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "Null Output"));
 
277
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");
 
278
 
 
279
    u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY);
 
280
    pa_sink_new_data_done(&data);
 
281
 
 
282
    if (!u->sink) {
 
283
        pa_log("Failed to create sink object.");
196
284
        goto fail;
197
285
    }
198
286
 
199
287
    u->sink->parent.process_msg = sink_process_msg;
 
288
    u->sink->update_requested_latency = sink_update_requested_latency_cb;
200
289
    u->sink->userdata = u;
201
 
    u->sink->flags = PA_SINK_LATENCY;
202
290
 
203
 
    pa_sink_set_module(u->sink, m);
204
291
    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
205
292
    pa_sink_set_rtpoll(u->sink, u->rtpoll);
206
 
    pa_sink_set_description(u->sink, pa_modargs_get_value(ma, "description", "NULL sink"));
207
 
 
208
 
    u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */
209
 
    if (u->block_size <= 0)
210
 
        u->block_size = pa_frame_size(&ss);
 
293
 
 
294
    pa_sink_set_latency_range(u->sink, (pa_usec_t) -1, MAX_LATENCY_USEC);
 
295
    u->block_usec = u->sink->thread_info.max_latency;
 
296
 
 
297
    u->sink->thread_info.max_rewind =
 
298
        u->sink->thread_info.max_request =
 
299
        pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
211
300
 
212
301
    if (!(u->thread = pa_thread_new(thread_func, u))) {
213
302
        pa_log("Failed to create thread.");