2 * Copyright (C) 2006-2009 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
8 * \file grab_client.c Functions for grabbing the stream at any position
11 * \sa filter_chain filter_chain_info filter.
15 #include <sys/types.h>
23 #include "buffer_tree.h"
25 #include "grab_client.h"
31 /** Grab clients that are not yet attached any btr node. */
32 static struct list_head inactive_grab_client_list
;
34 /** Grab clients that are attached to a btr node. */
35 static struct list_head active_grab_client_list
;
37 static int gc_write(struct grab_client
*gc
, char *buf
, size_t len
)
39 int ret
= write_ok(gc
->fd
);
43 if (ret
== 0) { /* fd not ready */
44 if (gc
->mode
== GM_PEDANTIC
)
46 if (gc
->mode
== GM_SLOPPY
)
49 ret
= write_nonblock(gc
->fd
, buf
, len
, 0);
55 if (gc
->mode
== GM_PEDANTIC
)
57 if (gc
->mode
== GM_SLOPPY
)
65 static void gc_pre_select(struct sched
*s
, struct task
*t
)
67 struct grab_client
*gc
= container_of(t
, struct grab_client
, task
);
68 int ret
= btr_node_status(gc
->btrn
, 0, BTR_NT_LEAF
);
73 s
->timeout
.tv_sec
= 0;
74 s
->timeout
.tv_usec
= 0;
77 para_fd_set(gc
->fd
, &s
->wfds
, &s
->max_fileno
);
81 * We need this forward declaration as post_select() needs
82 * activate_grab_client and vice versa.
84 static void gc_post_select(struct sched
*s
, struct task
*t
);
87 * Move a grab client to the active list and start it.
89 * \param gc The grab client to activate.
92 static void activate_grab_client(struct grab_client
*gc
)
94 struct btr_node
*root
= audiod_get_btr_root(), *parent
;
98 parent
= btr_search_node(gc
->parent
, root
);
101 PARA_INFO_LOG("activating %p (fd %d)\n", gc
, gc
->fd
);
102 list_move(&gc
->node
, &active_grab_client_list
);
103 gc
->btrn
= btr_new_node("grab", parent
, NULL
, NULL
);
104 if (!gc
->task
.pre_select
) {
105 gc
->task
.pre_select
= gc_pre_select
;
106 gc
->task
.post_select
= gc_post_select
;
107 sprintf(gc
->task
.status
, "grab");
108 register_task(&gc
->task
);
113 * Activate inactive grab clients if possible.
115 * This is called from audiod.c when the current audio file changes. It loops
116 * over all inactive grab clients and checks each grab client's configuration
117 * to determine if the client in question wishes to grab the new stream. If
118 * yes, this grab client is moved from the inactive to the active grab client list.
120 void activate_grab_clients(void)
122 struct grab_client
*gc
, *tmp
;
124 list_for_each_entry_safe(gc
, tmp
, &inactive_grab_client_list
, node
) {
125 if (gc
->task
.error
== -E_TASK_UNREGISTERED
) {
130 activate_grab_client(gc
);
134 static void add_inactive_gc(struct grab_client
*gc
)
136 PARA_INFO_LOG("adding grab client %p (fd %d) to inactive list\n",
138 para_list_add(&gc
->node
, &inactive_grab_client_list
);
141 static int gc_close(struct grab_client
*gc
, int err
)
143 btr_remove_node(gc
->btrn
);
144 btr_free_node(gc
->btrn
);
146 PARA_INFO_LOG("closing gc: %s\n", para_strerror(-err
));
147 list_move(&gc
->node
, &inactive_grab_client_list
);
148 if (err
== -E_GC_WRITE
|| (gc
->flags
& GF_ONE_SHOT
)) {
153 activate_grab_client(gc
);
157 static void gc_post_select(__a_unused
struct sched
*s
, struct task
*t
)
159 struct grab_client
*gc
= container_of(t
, struct grab_client
, task
);
160 struct btr_node
*btrn
= gc
->btrn
;
166 ret
= btr_node_status(btrn
, 0, BTR_NT_LEAF
);
171 sz
= btr_next_buffer(btrn
, &buf
);
173 ret
= gc_write(gc
, buf
, sz
);
177 btr_consume(btrn
, ret
);
180 t
->error
= gc_close(gc
, ret
)? ret
: 0;
183 static int check_gc_args(int argc
, char **argv
, struct grab_client
*gc
)
187 for (i
= 1; i
< argc
; i
++) {
188 const char *arg
= argv
[i
];
191 if (!strcmp(arg
, "--")) {
195 if (!strncmp(arg
, "-m", 2)) {
200 gc
->mode
= GM_SLOPPY
;
203 gc
->mode
= GM_AGGRESSIVE
;
206 gc
->mode
= GM_PEDANTIC
;
212 if (!strcmp(arg
, "-o")) {
213 gc
->flags
|= GF_ONE_SHOT
;
216 if (!strncmp(arg
, "-p=", 3)) {
217 gc
->parent
= para_strdup(arg
+ 3);
228 * Check the command line options and allocate a grab_client structure.
230 * \param fd The file descriptor of the client.
231 * \param argc Argument count.
232 * \param argv Argument vector.
234 * If the command line options given by \a argc and \a argv are valid.
235 * allocate a struct grab_client and initialize it with this valid
236 * configuration. Moreover, add the new grab client to the inactive list.
240 * \sa grab_client, inactive_grab_client_list, activate_grab_client,
241 * filter_node::callbacks.
243 int grab_client_new(int fd
, int argc
, char **argv
)
246 struct grab_client
*gc
= para_calloc(sizeof(struct grab_client
));
248 ret
= check_gc_args(argc
, argv
, gc
);
253 activate_grab_client(gc
);
261 * Initialize the grabbing subsystem.
263 * This has to be called once during startup before any other function from
264 * grab_client.c may be used. It initializes \a inactive_grab_client_list.
266 void init_grabbing(void)
268 PARA_INFO_LOG("grab init\n");
269 INIT_LIST_HEAD(&inactive_grab_client_list
);
270 INIT_LIST_HEAD(&active_grab_client_list
);