153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
753a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
853a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
953a5a1b3Sopenharmony_ci  or (at your option) any later version.
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1253a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1353a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1453a5a1b3Sopenharmony_ci  General Public License for more details.
1553a5a1b3Sopenharmony_ci
1653a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1753a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1853a5a1b3Sopenharmony_ci***/
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2153a5a1b3Sopenharmony_ci#include <config.h>
2253a5a1b3Sopenharmony_ci#endif
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
2553a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
2653a5a1b3Sopenharmony_ci#include <pulsecore/flist.h>
2753a5a1b3Sopenharmony_ci#include <pulse/fork-detect.h>
2853a5a1b3Sopenharmony_ci
2953a5a1b3Sopenharmony_ci#include "internal.h"
3053a5a1b3Sopenharmony_ci#include "operation.h"
3153a5a1b3Sopenharmony_ci
3253a5a1b3Sopenharmony_ciPA_STATIC_FLIST_DECLARE(operations, 0, pa_xfree);
3353a5a1b3Sopenharmony_ci
3453a5a1b3Sopenharmony_cipa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, void *userdata) {
3553a5a1b3Sopenharmony_ci    pa_operation *o;
3653a5a1b3Sopenharmony_ci    pa_assert(c);
3753a5a1b3Sopenharmony_ci
3853a5a1b3Sopenharmony_ci    if (!(o = pa_flist_pop(PA_STATIC_FLIST_GET(operations))))
3953a5a1b3Sopenharmony_ci        o = pa_xnew(pa_operation, 1);
4053a5a1b3Sopenharmony_ci
4153a5a1b3Sopenharmony_ci    pa_zero(*o);
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_ci    PA_REFCNT_INIT(o);
4453a5a1b3Sopenharmony_ci    o->context = c;
4553a5a1b3Sopenharmony_ci    o->stream = s;
4653a5a1b3Sopenharmony_ci
4753a5a1b3Sopenharmony_ci    o->state = PA_OPERATION_RUNNING;
4853a5a1b3Sopenharmony_ci    o->callback = cb;
4953a5a1b3Sopenharmony_ci    o->userdata = userdata;
5053a5a1b3Sopenharmony_ci
5153a5a1b3Sopenharmony_ci    /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */
5253a5a1b3Sopenharmony_ci    PA_LLIST_PREPEND(pa_operation, c->operations, o);
5353a5a1b3Sopenharmony_ci    pa_operation_ref(o);
5453a5a1b3Sopenharmony_ci
5553a5a1b3Sopenharmony_ci    return o;
5653a5a1b3Sopenharmony_ci}
5753a5a1b3Sopenharmony_ci
5853a5a1b3Sopenharmony_cipa_operation *pa_operation_ref(pa_operation *o) {
5953a5a1b3Sopenharmony_ci    pa_assert(o);
6053a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(o) >= 1);
6153a5a1b3Sopenharmony_ci
6253a5a1b3Sopenharmony_ci    PA_REFCNT_INC(o);
6353a5a1b3Sopenharmony_ci    return o;
6453a5a1b3Sopenharmony_ci}
6553a5a1b3Sopenharmony_ci
6653a5a1b3Sopenharmony_civoid pa_operation_unref(pa_operation *o) {
6753a5a1b3Sopenharmony_ci    pa_assert(o);
6853a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(o) >= 1);
6953a5a1b3Sopenharmony_ci
7053a5a1b3Sopenharmony_ci    if (PA_REFCNT_DEC(o) <= 0) {
7153a5a1b3Sopenharmony_ci        pa_assert(!o->context);
7253a5a1b3Sopenharmony_ci        pa_assert(!o->stream);
7353a5a1b3Sopenharmony_ci
7453a5a1b3Sopenharmony_ci        if (pa_flist_push(PA_STATIC_FLIST_GET(operations), o) < 0)
7553a5a1b3Sopenharmony_ci            pa_xfree(o);
7653a5a1b3Sopenharmony_ci    }
7753a5a1b3Sopenharmony_ci}
7853a5a1b3Sopenharmony_ci
7953a5a1b3Sopenharmony_cistatic void operation_unlink(pa_operation *o) {
8053a5a1b3Sopenharmony_ci    pa_assert(o);
8153a5a1b3Sopenharmony_ci
8253a5a1b3Sopenharmony_ci    if (o->context) {
8353a5a1b3Sopenharmony_ci        pa_assert(PA_REFCNT_VALUE(o) >= 2);
8453a5a1b3Sopenharmony_ci
8553a5a1b3Sopenharmony_ci        PA_LLIST_REMOVE(pa_operation, o->context->operations, o);
8653a5a1b3Sopenharmony_ci        pa_operation_unref(o);
8753a5a1b3Sopenharmony_ci
8853a5a1b3Sopenharmony_ci        o->context = NULL;
8953a5a1b3Sopenharmony_ci    }
9053a5a1b3Sopenharmony_ci
9153a5a1b3Sopenharmony_ci    o->stream = NULL;
9253a5a1b3Sopenharmony_ci    o->callback = NULL;
9353a5a1b3Sopenharmony_ci    o->userdata = NULL;
9453a5a1b3Sopenharmony_ci    o->state_callback = NULL;
9553a5a1b3Sopenharmony_ci    o->state_userdata = NULL;
9653a5a1b3Sopenharmony_ci}
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_cistatic void operation_set_state(pa_operation *o, pa_operation_state_t st) {
9953a5a1b3Sopenharmony_ci    pa_assert(o);
10053a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(o) >= 1);
10153a5a1b3Sopenharmony_ci
10253a5a1b3Sopenharmony_ci    if (st == o->state)
10353a5a1b3Sopenharmony_ci        return;
10453a5a1b3Sopenharmony_ci
10553a5a1b3Sopenharmony_ci    if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED))
10653a5a1b3Sopenharmony_ci        return;
10753a5a1b3Sopenharmony_ci
10853a5a1b3Sopenharmony_ci    pa_operation_ref(o);
10953a5a1b3Sopenharmony_ci
11053a5a1b3Sopenharmony_ci    o->state = st;
11153a5a1b3Sopenharmony_ci
11253a5a1b3Sopenharmony_ci    if (o->state_callback)
11353a5a1b3Sopenharmony_ci        o->state_callback(o, o->state_userdata);
11453a5a1b3Sopenharmony_ci
11553a5a1b3Sopenharmony_ci    if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED))
11653a5a1b3Sopenharmony_ci        operation_unlink(o);
11753a5a1b3Sopenharmony_ci
11853a5a1b3Sopenharmony_ci    pa_operation_unref(o);
11953a5a1b3Sopenharmony_ci}
12053a5a1b3Sopenharmony_ci
12153a5a1b3Sopenharmony_civoid pa_operation_cancel(pa_operation *o) {
12253a5a1b3Sopenharmony_ci    pa_assert(o);
12353a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(o) >= 1);
12453a5a1b3Sopenharmony_ci
12553a5a1b3Sopenharmony_ci    operation_set_state(o, PA_OPERATION_CANCELED);
12653a5a1b3Sopenharmony_ci}
12753a5a1b3Sopenharmony_ci
12853a5a1b3Sopenharmony_civoid pa_operation_done(pa_operation *o) {
12953a5a1b3Sopenharmony_ci    pa_assert(o);
13053a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(o) >= 1);
13153a5a1b3Sopenharmony_ci
13253a5a1b3Sopenharmony_ci    operation_set_state(o, PA_OPERATION_DONE);
13353a5a1b3Sopenharmony_ci}
13453a5a1b3Sopenharmony_ci
13553a5a1b3Sopenharmony_cipa_operation_state_t pa_operation_get_state(const pa_operation *o) {
13653a5a1b3Sopenharmony_ci    pa_assert(o);
13753a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(o) >= 1);
13853a5a1b3Sopenharmony_ci
13953a5a1b3Sopenharmony_ci    return o->state;
14053a5a1b3Sopenharmony_ci}
14153a5a1b3Sopenharmony_ci
14253a5a1b3Sopenharmony_civoid pa_operation_set_state_callback(pa_operation *o, pa_operation_notify_cb_t cb, void *userdata) {
14353a5a1b3Sopenharmony_ci    pa_assert(o);
14453a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(o) >= 1);
14553a5a1b3Sopenharmony_ci
14653a5a1b3Sopenharmony_ci    if (pa_detect_fork())
14753a5a1b3Sopenharmony_ci        return;
14853a5a1b3Sopenharmony_ci
14953a5a1b3Sopenharmony_ci    if (o->state == PA_OPERATION_DONE || o->state == PA_OPERATION_CANCELED)
15053a5a1b3Sopenharmony_ci        return;
15153a5a1b3Sopenharmony_ci
15253a5a1b3Sopenharmony_ci    o->state_callback = cb;
15353a5a1b3Sopenharmony_ci    o->state_userdata = userdata;
15453a5a1b3Sopenharmony_ci}
155