~diwic/ubuntu/lucid/pulseaudio/bugfixes

« back to all changes in this revision

Viewing changes to src/pulsecore/source-output.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2009-05-05 14:18:20 UTC
  • mfrom: (1.2.4 upstream) (1.1.8 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090505141820-rrr2mtdd1jkllvr8
Tags: 1:0.9.15-1ubuntu1
* Merge from unreleased Debian pulseaudio git, remaining changes:
  - epoch (my stupid fault :S)
  - Don't build against, and create jack package. Jack is not in main
  - use linear resampler to work better with lack of PREEMPT in jaunty's
    -generic kernel config, also change buffer size
  - Add alsa configuration files to route alsa applications via pulseaudio
  - Move libasound2-plugins from Recommends to Depends
  - Add pm-utils sleep hook to suspend (and resume) users' pulseaudio
    daemons
  - patch to fix source/sink and suspend-on-idle race
  - Make initscript more informative in the default case of per-user
    sessions
  - create /var/run/pulse, and make restart more robust
  - add status check for system wide pulseaudio instance
  - LSB {Required-*,Should-*} should specify hal instead of dbus,
    since hal is required (and already requires dbus)
  - indicate that the system pulseaudio instance is being started from the init
    script
  - Install more upstream man pages
  - Link to pacat for parec man page
  - check whether pulseaudio is running before preloading the padsp library
  - Add DEB_OPT_FLAG = -O3 as per recommendation from
    pulseaudio-discuss/2007-December/001017.html
  - cache /usr/share/sounds/ubuntu/stereo/ wav files on pulseaudio load
  - disable glitch free (use tsched=0)
  - Generate a PO template on build
  - add special case to disable pulseaudio loading if accessibility/speech
    is being used
  - the sd wrapper script should not load pulseaudio if pulseaudio is being
    used as a system service
  - add a pulseaudio apport hook
  - fix some typos in README.Debian
  - demote paprefs to suggests
  - drop padevchooser(Recommends) and pavucontrol (Suggests)
  - drop libasyncns-dev build dependency, its in universe
* add libudev-dev as a build-dependency

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 
6
6
  PulseAudio is free software; you can redistribute it and/or modify
7
7
  it under the terms of the GNU Lesser General Public License as published
8
 
  by the Free Software Foundation; either version 2 of the License,
 
8
  by the Free Software Foundation; either version 2.1 of the License,
9
9
  or (at your option) any later version.
10
10
 
11
11
  PulseAudio is distributed in the hope that it will be useful, but
29
29
 
30
30
#include <pulse/utf8.h>
31
31
#include <pulse/xmalloc.h>
 
32
#include <pulse/util.h>
32
33
 
33
34
#include <pulsecore/sample-util.h>
34
35
#include <pulsecore/core-subscribe.h>
86
87
    o->attach = NULL;
87
88
    o->detach = NULL;
88
89
    o->suspend = NULL;
89
 
    o->moved = NULL;
 
90
    o->suspend_within_thread = NULL;
 
91
    o->moving = NULL;
90
92
    o->kill = NULL;
91
93
    o->get_latency = NULL;
92
94
    o->state_change = NULL;
 
95
    o->may_move_to = NULL;
 
96
    o->send_event = NULL;
93
97
}
94
98
 
95
99
/* Called from main context */
96
 
pa_source_output* pa_source_output_new(
 
100
int pa_source_output_new(
 
101
        pa_source_output**_o,
97
102
        pa_core *core,
98
103
        pa_source_output_new_data *data,
99
104
        pa_source_output_flags_t flags) {
101
106
    pa_source_output *o;
102
107
    pa_resampler *resampler = NULL;
103
108
    char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
 
109
    int r;
104
110
 
 
111
    pa_assert(_o);
105
112
    pa_assert(core);
106
113
    pa_assert(data);
107
114
 
108
 
    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data) < 0)
109
 
        return NULL;
110
 
 
111
 
    pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
112
 
 
113
 
    if (!data->source)
114
 
        data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, TRUE);
115
 
 
116
 
    pa_return_null_if_fail(data->source);
117
 
    pa_return_null_if_fail(pa_source_get_state(data->source) != PA_SOURCE_UNLINKED);
118
 
 
119
 
    pa_return_null_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of);
 
115
    if (data->client)
 
116
        pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist);
 
117
 
 
118
    if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data)) < 0)
 
119
        return r;
 
120
 
 
121
    pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID);
 
122
 
 
123
    if (!data->source) {
 
124
        data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE);
 
125
        data->save_source = FALSE;
 
126
    }
 
127
 
 
128
    pa_return_val_if_fail(data->source, -PA_ERR_NOENTITY);
 
129
    pa_return_val_if_fail(PA_SOURCE_IS_LINKED(pa_source_get_state(data->source)), -PA_ERR_BADSTATE);
 
130
    pa_return_val_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of, -PA_ERR_INVALID);
120
131
 
121
132
    if (!data->sample_spec_is_set)
122
133
        data->sample_spec = data->source->sample_spec;
123
134
 
124
 
    pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec));
 
135
    pa_return_val_if_fail(pa_sample_spec_valid(&data->sample_spec), -PA_ERR_INVALID);
125
136
 
126
137
    if (!data->channel_map_is_set) {
127
 
        if (data->source->channel_map.channels == data->sample_spec.channels)
 
138
        if (pa_channel_map_compatible(&data->source->channel_map, &data->sample_spec))
128
139
            data->channel_map = data->source->channel_map;
129
140
        else
130
141
            pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
131
142
    }
132
143
 
133
 
    pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
134
 
    pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
 
144
    pa_return_val_if_fail(pa_channel_map_valid(&data->channel_map), -PA_ERR_INVALID);
 
145
    pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID);
135
146
 
136
147
    if (flags & PA_SOURCE_OUTPUT_FIX_FORMAT)
137
148
        data->sample_spec.format = data->source->sample_spec.format;
150
161
    if (data->resample_method == PA_RESAMPLER_INVALID)
151
162
        data->resample_method = core->resample_method;
152
163
 
153
 
    pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX);
154
 
 
155
 
    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data) < 0)
156
 
        return NULL;
 
164
    pa_return_val_if_fail(data->resample_method < PA_RESAMPLER_MAX, -PA_ERR_INVALID);
 
165
 
 
166
    if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data)) < 0)
 
167
        return r;
 
168
 
 
169
    if ((flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND) &&
 
170
        pa_source_get_state(data->source) == PA_SOURCE_SUSPENDED) {
 
171
        pa_log("Failed to create source output: source is suspended.");
 
172
        return -PA_ERR_BADSTATE;
 
173
    }
157
174
 
158
175
    if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
159
176
        pa_log("Failed to create source output: too many outputs per source.");
160
 
        return NULL;
 
177
        return -PA_ERR_TOOLARGE;
161
178
    }
162
179
 
163
180
    if ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
174
191
                      (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
175
192
                      (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) {
176
193
            pa_log_warn("Unsupported resampling operation.");
177
 
            return NULL;
 
194
            return -PA_ERR_NOTSUPPORTED;
178
195
        }
179
 
 
180
 
        data->resample_method = pa_resampler_get_method(resampler);
181
196
    }
182
197
 
183
198
    o = pa_msgobject_new(pa_source_output);
188
203
    o->state = PA_SOURCE_OUTPUT_INIT;
189
204
    o->flags = flags;
190
205
    o->proplist = pa_proplist_copy(data->proplist);
191
 
    o->driver = pa_xstrdup(data->driver);
 
206
    o->driver = pa_xstrdup(pa_path_get_filename(data->driver));
192
207
    o->module = data->module;
193
208
    o->source = data->source;
194
209
    o->client = data->client;
195
210
 
196
 
    o->resample_method = data->resample_method;
 
211
    o->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID;
 
212
    o->requested_resample_method = data->resample_method;
197
213
    o->sample_spec = data->sample_spec;
198
214
    o->channel_map = data->channel_map;
199
215
 
200
216
    o->direct_on_input = data->direct_on_input;
201
217
 
 
218
    o->save_source = data->save_source;
 
219
 
202
220
    reset_callbacks(o);
203
221
    o->userdata = NULL;
204
222
 
222
240
    pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0);
223
241
    pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0);
224
242
 
 
243
    if (o->client)
 
244
        pa_assert_se(pa_idxset_put(o->client->source_outputs, o, NULL) >= 0);
 
245
 
225
246
    if (o->direct_on_input)
226
247
        pa_assert_se(pa_idxset_put(o->direct_on_input->direct_outputs, o, NULL) == 0);
227
248
 
234
255
 
235
256
    /* Don't forget to call pa_source_output_put! */
236
257
 
237
 
    return o;
 
258
    *_o = o;
 
259
    return 0;
238
260
}
239
261
 
240
262
/* Called from main context */
241
263
static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) {
242
264
    pa_assert(o);
243
265
 
 
266
    if (!o->source)
 
267
        return;
 
268
 
244
269
    if (o->state == PA_SOURCE_OUTPUT_CORKED && state != PA_SOURCE_OUTPUT_CORKED)
245
270
        pa_assert_se(o->source->n_corked -- >= 1);
246
271
    else if (o->state != PA_SOURCE_OUTPUT_CORKED && state == PA_SOURCE_OUTPUT_CORKED)
247
272
        o->source->n_corked++;
248
 
 
249
 
    pa_source_update_status(o->source);
250
273
}
251
274
 
252
275
/* Called from main context */
253
 
static int source_output_set_state(pa_source_output *o, pa_source_output_state_t state) {
 
276
static void source_output_set_state(pa_source_output *o, pa_source_output_state_t state) {
254
277
    pa_assert(o);
255
278
 
256
279
    if (o->state == state)
257
 
        return 0;
 
280
        return;
258
281
 
259
282
    pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
260
283
 
262
285
    o->state = state;
263
286
 
264
287
    if (state != PA_SOURCE_OUTPUT_UNLINKED)
265
 
        pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], o);
 
288
        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], o);
266
289
 
267
 
    return 0;
 
290
    pa_source_update_status(o->source);
268
291
}
269
292
 
270
293
/* Called from main context */
280
303
    linked = PA_SOURCE_OUTPUT_IS_LINKED(o->state);
281
304
 
282
305
    if (linked)
283
 
        pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o);
 
306
        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o);
284
307
 
285
308
    if (o->direct_on_input)
286
309
        pa_idxset_remove_by_data(o->direct_on_input->direct_outputs, o, NULL);
287
 
    pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL);
288
 
    if (pa_idxset_remove_by_data(o->source->outputs, o, NULL))
289
 
        pa_source_output_unref(o);
 
310
 
 
311
    pa_idxset_remove_by_data(o->core->source_outputs, o, NULL);
 
312
 
 
313
    if (o->source)
 
314
        if (pa_idxset_remove_by_data(o->source->outputs, o, NULL))
 
315
            pa_source_output_unref(o);
 
316
 
 
317
    if (o->client)
 
318
        pa_idxset_remove_by_data(o->client->source_outputs, o, NULL);
290
319
 
291
320
    update_n_corked(o, PA_SOURCE_OUTPUT_UNLINKED);
292
321
    o->state = PA_SOURCE_OUTPUT_UNLINKED;
293
322
 
294
 
    if (linked)
 
323
    if (linked && o->source)
295
324
        if (o->source->asyncmsgq)
296
325
            pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0);
297
326
 
298
327
    reset_callbacks(o);
299
328
 
300
329
    if (linked) {
301
 
        pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index);
302
 
        pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o);
303
 
    }
304
 
 
305
 
    o->source = NULL;
 
330
        pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index);
 
331
        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o);
 
332
    }
 
333
 
 
334
    if (o->source) {
 
335
        pa_source_update_status(o->source);
 
336
        o->source = NULL;
 
337
    }
 
338
 
 
339
    pa_core_maybe_vacuum(o->core);
 
340
 
306
341
    pa_source_output_unref(o);
307
342
}
308
343
 
351
386
 
352
387
    pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0);
353
388
 
354
 
    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index);
355
 
    pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], o);
 
389
    pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index);
 
390
    pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], o);
 
391
 
 
392
    pa_source_update_status(o->source);
356
393
}
357
394
 
358
395
/* Called from main context */
398
435
 
399
436
    if (pa_memblockq_push(o->thread_info.delay_memblockq, chunk) < 0) {
400
437
        pa_log_debug("Delay queue overflow!");
401
 
        pa_memblockq_seek(o->thread_info.delay_memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE);
 
438
        pa_memblockq_seek(o->thread_info.delay_memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
402
439
    }
403
440
 
404
441
    limit = o->process_rewind ? 0 : o->source->thread_info.max_rewind;
405
442
 
 
443
    if (limit > 0 && o->source->monitor_of) {
 
444
        pa_usec_t latency;
 
445
        size_t n;
 
446
 
 
447
        /* Hmm, check the latency for knowing how much of the buffered
 
448
         * data is actually still unplayed and might hence still
 
449
         * change. This is suboptimal. Ideally we'd have a call like
 
450
         * pa_sink_get_changeable_size() or so that tells us how much
 
451
         * of the queued data is actually still changeable. Hence
 
452
         * FIXME! */
 
453
 
 
454
        latency = pa_sink_get_latency_within_thread(o->source->monitor_of);
 
455
 
 
456
        n = pa_usec_to_bytes(latency, &o->source->sample_spec);
 
457
 
 
458
        if (n < limit)
 
459
            limit = n;
 
460
    }
 
461
 
406
462
    /* Implement the delay queue */
407
463
    while ((length = pa_memblockq_get_length(o->thread_info.delay_memblockq)) > limit) {
408
464
        pa_memchunk qchunk;
480
536
}
481
537
 
482
538
/* Called from thread context */
483
 
static pa_usec_t fixup_latency(pa_source *s, pa_usec_t usec) {
484
 
    pa_source_assert_ref(s);
485
 
 
486
 
    if (usec == (pa_usec_t) -1)
487
 
        return usec;
488
 
 
489
 
    if (s->thread_info.max_latency > 0 && usec > s->thread_info.max_latency)
490
 
        usec = s->thread_info.max_latency;
491
 
 
492
 
    if (s->thread_info.min_latency > 0 && usec < s->thread_info.min_latency)
493
 
        usec = s->thread_info.min_latency;
494
 
 
495
 
    return usec;
496
 
}
497
 
 
498
 
/* Called from thread context */
499
539
pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec) {
500
540
    pa_source_output_assert_ref(o);
501
541
 
502
 
    usec = fixup_latency(o->source, usec);
 
542
    if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY))
 
543
        usec = o->source->fixed_latency;
 
544
 
 
545
    if (usec != (pa_usec_t) -1)
 
546
        usec = PA_CLAMP(usec, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
 
547
 
503
548
    o->thread_info.requested_source_latency = usec;
504
549
    pa_source_invalidate_requested_latency(o->source);
505
550
 
510
555
pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) {
511
556
    pa_source_output_assert_ref(o);
512
557
 
513
 
    if (PA_SOURCE_OUTPUT_IS_LINKED(o->state))
 
558
    if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) {
514
559
        pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
515
 
    else
516
 
        /* If this source output is not realized yet, we have to touch
517
 
         * the thread info data directly */
518
 
 
519
 
        o->thread_info.requested_source_latency = usec;
 
560
        return usec;
 
561
    }
 
562
 
 
563
    /* If this source output is not realized yet or is being moved, we
 
564
     * have to touch the thread info data directly */
 
565
 
 
566
    if (o->source) {
 
567
        if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY))
 
568
            usec = o->source->fixed_latency;
 
569
 
 
570
        if (usec != (pa_usec_t) -1) {
 
571
            pa_usec_t min_latency, max_latency;
 
572
            pa_source_get_latency_range(o->source, &min_latency, &max_latency);
 
573
            usec = PA_CLAMP(usec, min_latency, max_latency);
 
574
        }
 
575
    }
 
576
 
 
577
    o->thread_info.requested_source_latency = usec;
520
578
 
521
579
    return usec;
522
580
}
523
581
 
524
582
/* Called from main context */
525
583
pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) {
526
 
    pa_usec_t usec = 0;
527
 
 
528
584
    pa_source_output_assert_ref(o);
529
585
 
530
 
    if (PA_SOURCE_OUTPUT_IS_LINKED(o->state))
 
586
    if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) {
 
587
        pa_usec_t usec = 0;
531
588
        pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
532
 
    else
533
 
        /* If this source output is not realized yet, we have to touch
534
 
         * the thread info data directly */
535
 
        usec = o->thread_info.requested_source_latency;
536
 
 
537
 
    return usec;
 
589
        return usec;
 
590
    }
 
591
 
 
592
    /* If this source output is not realized yet or is being moved, we
 
593
     * have to touch the thread info data directly */
 
594
 
 
595
    return o->thread_info.requested_source_latency;
538
596
}
539
597
 
540
598
/* Called from main context */
549
607
int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
550
608
    pa_source_output_assert_ref(o);
551
609
    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
552
 
    pa_return_val_if_fail(o->thread_info.resampler, -1);
 
610
    pa_return_val_if_fail(o->thread_info.resampler, -PA_ERR_BADSTATE);
553
611
 
554
612
    if (o->sample_spec.rate == rate)
555
613
        return 0;
558
616
 
559
617
    pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, NULL);
560
618
 
561
 
    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
 
619
    pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
562
620
    return 0;
563
621
}
564
622
 
581
639
        pa_proplist_unset(o->proplist, PA_PROP_MEDIA_NAME);
582
640
 
583
641
    if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) {
584
 
        pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
585
 
        pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
 
642
        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
 
643
        pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
 
644
    }
 
645
}
 
646
 
 
647
/* Called from main thread */
 
648
void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p) {
 
649
    pa_source_output_assert_ref(o);
 
650
 
 
651
    if (p)
 
652
        pa_proplist_update(o->proplist, mode, p);
 
653
 
 
654
    if (PA_SINK_IS_LINKED(o->state)) {
 
655
        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
 
656
        pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
586
657
    }
587
658
}
588
659
 
590
661
pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
591
662
    pa_source_output_assert_ref(o);
592
663
 
593
 
    return o->resample_method;
 
664
    return o->actual_resample_method;
594
665
}
595
666
 
596
667
/* Called from main context */
597
 
int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
598
 
    pa_source *origin;
599
 
    pa_resampler *new_resampler;
600
 
    pa_source_output_move_hook_data hook_data;
601
 
 
 
668
pa_bool_t pa_source_output_may_move(pa_source_output *o) {
602
669
    pa_source_output_assert_ref(o);
603
670
    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
604
 
    pa_source_assert_ref(dest);
605
 
 
606
 
    origin = o->source;
607
 
 
608
 
    if (dest == origin)
609
 
        return 0;
610
671
 
611
672
    if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE)
612
 
        return -1;
 
673
        return FALSE;
613
674
 
614
675
    if (o->direct_on_input)
615
 
        return -1;
 
676
        return FALSE;
 
677
 
 
678
    return TRUE;
 
679
}
 
680
 
 
681
/* Called from main context */
 
682
pa_bool_t pa_source_output_may_move_to(pa_source_output *o, pa_source *dest) {
 
683
    pa_source_output_assert_ref(o);
 
684
    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
 
685
    pa_source_assert_ref(dest);
 
686
 
 
687
    if (dest == o->source)
 
688
        return TRUE;
 
689
 
 
690
    if (!pa_source_output_may_move(o))
 
691
        return FALSE;
616
692
 
617
693
    if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
618
694
        pa_log_warn("Failed to move source output: too many outputs per source.");
 
695
        return FALSE;
 
696
    }
 
697
 
 
698
    if (o->may_move_to)
 
699
        if (!o->may_move_to(o, dest))
 
700
            return FALSE;
 
701
 
 
702
    return TRUE;
 
703
}
 
704
 
 
705
/* Called from main context */
 
706
int pa_source_output_start_move(pa_source_output *o) {
 
707
    pa_source *origin;
 
708
    int r;
 
709
 
 
710
    pa_source_output_assert_ref(o);
 
711
    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
 
712
    pa_assert(o->source);
 
713
 
 
714
    if (!pa_source_output_may_move(o))
 
715
        return -PA_ERR_NOTSUPPORTED;
 
716
 
 
717
    if ((r = pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], o)) < 0)
 
718
        return r;
 
719
 
 
720
    origin = o->source;
 
721
 
 
722
    pa_idxset_remove_by_data(o->source->outputs, o, NULL);
 
723
 
 
724
    if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED)
 
725
        pa_assert_se(origin->n_corked-- >= 1);
 
726
 
 
727
    pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0);
 
728
 
 
729
    pa_source_update_status(o->source);
 
730
    o->source = NULL;
 
731
 
 
732
    pa_source_output_unref(o);
 
733
 
 
734
    return 0;
 
735
}
 
736
 
 
737
/* Called from main context */
 
738
int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t save) {
 
739
    pa_resampler *new_resampler;
 
740
 
 
741
    pa_source_output_assert_ref(o);
 
742
    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
 
743
    pa_assert(!o->source);
 
744
    pa_source_assert_ref(dest);
 
745
 
 
746
    if (!pa_source_output_may_move_to(o, dest))
619
747
        return -1;
620
 
    }
621
748
 
622
749
    if (o->thread_info.resampler &&
623
 
        pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) &&
624
 
        pa_channel_map_equal(&origin->channel_map, &dest->channel_map))
 
750
        pa_sample_spec_equal(pa_resampler_input_sample_spec(o->thread_info.resampler), &dest->sample_spec) &&
 
751
        pa_channel_map_equal(pa_resampler_input_channel_map(o->thread_info.resampler), &dest->channel_map))
625
752
 
626
753
        /* Try to reuse the old resampler if possible */
627
754
        new_resampler = o->thread_info.resampler;
633
760
        /* Okey, we need a new resampler for the new source */
634
761
 
635
762
        if (!(new_resampler = pa_resampler_new(
636
 
                      dest->core->mempool,
 
763
                      o->core->mempool,
637
764
                      &dest->sample_spec, &dest->channel_map,
638
765
                      &o->sample_spec, &o->channel_map,
639
 
                      o->resample_method,
 
766
                      o->requested_resample_method,
640
767
                      ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
641
768
                      ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
642
769
                      (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
643
770
            pa_log_warn("Unsupported resampling operation.");
644
 
            return -1;
 
771
            return -PA_ERR_NOTSUPPORTED;
645
772
        }
646
773
    } else
647
774
        new_resampler = NULL;
648
775
 
649
 
    hook_data.source_output = o;
650
 
    hook_data.destination = dest;
651
 
    pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], &hook_data);
652
 
 
653
 
    /* Okey, let's move it */
654
 
    pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0);
655
 
 
656
 
    pa_idxset_remove_by_data(origin->outputs, o, NULL);
657
 
    pa_idxset_put(dest->outputs, o, NULL);
 
776
    if (o->moving)
 
777
        o->moving(o, dest);
 
778
 
658
779
    o->source = dest;
 
780
    o->save_source = save;
 
781
    pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL);
659
782
 
660
 
    if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) {
661
 
        pa_assert_se(origin->n_corked-- >= 1);
662
 
        dest->n_corked++;
663
 
    }
 
783
    if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED)
 
784
        o->source->n_corked++;
664
785
 
665
786
    /* Replace resampler */
666
787
    if (new_resampler != o->thread_info.resampler) {
681
802
                &o->source->silence);
682
803
    }
683
804
 
684
 
    pa_source_update_status(origin);
685
805
    pa_source_update_status(dest);
686
806
 
687
807
    pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0);
688
808
 
689
 
    if (o->moved)
690
 
        o->moved(o);
691
 
 
692
 
    pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST], o);
693
 
 
694
 
    pa_log_debug("Successfully moved source output %i from %s to %s.", o->index, origin->name, dest->name);
 
809
    pa_log_debug("Successfully moved source output %i to %s.", o->index, dest->name);
695
810
 
696
811
    /* Notify everyone */
697
 
    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
 
812
    pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], o);
 
813
    pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
 
814
 
 
815
    return 0;
 
816
}
 
817
 
 
818
/* Called from main context */
 
819
int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t save) {
 
820
    int r;
 
821
 
 
822
    pa_source_output_assert_ref(o);
 
823
    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
 
824
    pa_assert(o->source);
 
825
    pa_source_assert_ref(dest);
 
826
 
 
827
    if (dest == o->source)
 
828
        return 0;
 
829
 
 
830
    if (!pa_source_output_may_move_to(o, dest))
 
831
        return -PA_ERR_NOTSUPPORTED;
 
832
 
 
833
    pa_source_output_ref(o);
 
834
 
 
835
    if ((r = pa_source_output_start_move(o)) < 0) {
 
836
        pa_source_output_unref(o);
 
837
        return r;
 
838
    }
 
839
 
 
840
    if ((r = pa_source_output_finish_move(o, dest, save)) < 0) {
 
841
        pa_source_output_unref(o);
 
842
        return r;
 
843
    }
 
844
 
 
845
    pa_source_output_unref(o);
698
846
 
699
847
    return 0;
700
848
}
721
869
 
722
870
        case PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY: {
723
871
            pa_usec_t *r = userdata;
724
 
            pa_usec_t source_usec = 0;
725
872
 
726
873
            r[0] += pa_bytes_to_usec(pa_memblockq_get_length(o->thread_info.delay_memblockq), &o->source->sample_spec);
727
 
 
728
 
            if (o->source->parent.process_msg(PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_GET_LATENCY, &source_usec, 0, NULL) >= 0)
729
 
                r[1] += source_usec;
 
874
            r[1] += pa_source_get_latency_within_thread(o->source);
730
875
 
731
876
            return 0;
732
877
        }
758
903
        }
759
904
    }
760
905
 
761
 
    return -1;
 
906
    return -PA_ERR_NOTIMPLEMENTED;
 
907
}
 
908
 
 
909
void pa_source_output_send_event(pa_source_output *o, const char *event, pa_proplist *data) {
 
910
    pa_proplist *pl = NULL;
 
911
    pa_source_output_send_event_hook_data hook_data;
 
912
 
 
913
    pa_source_output_assert_ref(o);
 
914
    pa_assert(event);
 
915
 
 
916
    if (!o->send_event)
 
917
        return;
 
918
 
 
919
    if (!data)
 
920
        data = pl = pa_proplist_new();
 
921
 
 
922
    hook_data.source_output = o;
 
923
    hook_data.data = data;
 
924
    hook_data.event = event;
 
925
 
 
926
    if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT], &hook_data) < 0)
 
927
        goto finish;
 
928
 
 
929
    o->send_event(o, event, data);
 
930
 
 
931
finish:
 
932
    if (pl)
 
933
        pa_proplist_free(pl);
762
934
}