2 * Copyright (C) 2011-2013 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file afh_recv.c Receiver for streaming local files. */
10 #include <sys/types.h>
18 #include "buffer_tree.h"
20 #include "afh_recv.cmdline.h"
25 struct private_afh_recv_data
{
31 long unsigned first_chunk
;
32 long unsigned last_chunk
;
33 struct timeval stream_start
;
34 uint32_t current_chunk
;
37 static int afh_execute(struct btr_node
*btrn
, const char *cmd
, char **result
)
39 struct receiver_node
*rn
= btr_context(btrn
);
40 struct private_afh_recv_data
*pard
= rn
->private_data
;
43 if (!strcmp(cmd
, "seconds_total")) {
44 *result
= make_message("%lu", pard
->afhi
.seconds_total
);
47 if (!strcmp(cmd
, "chunks_total")) {
48 *result
= make_message("%lu", pard
->afhi
.chunks_total
);
51 if (!strcmp(cmd
, "afhi")) {
52 afh_get_afhi_txt(pard
->audio_format_num
, &pard
->afhi
, result
);
55 if (!strncmp(cmd
, "repos", 5)) {
57 int ret
= para_atoi32(cmd
+ 5, &x
);
60 if (x
>= pard
->afhi
.chunks_total
)
61 return -ERRNO_TO_PARA_ERROR(EINVAL
);
62 pard
->first_chunk
= pard
->current_chunk
= x
;
69 static void *afh_recv_parse_config(int argc
, char **argv
)
71 struct afh_recv_args_info
*tmp
= para_calloc(sizeof(*tmp
));
73 afh_recv_cmdline_parser(argc
, argv
, tmp
);
77 static void afh_recv_free_config(void *conf
)
81 afh_recv_cmdline_parser_free(conf
);
85 static int afh_recv_open(struct receiver_node
*rn
)
87 struct afh_recv_args_info
*conf
= rn
->conf
;
88 struct private_afh_recv_data
*pard
;
89 struct afh_info
*afhi
;
90 char *filename
= conf
->filename_arg
;
94 if (!filename
|| *filename
== '\0')
95 return -E_AFH_RECV_BAD_FILENAME
;
96 rn
->private_data
= pard
= para_calloc(sizeof(*pard
));
98 ret
= mmap_full_file(filename
, O_RDONLY
, &pard
->map
,
99 &pard
->map_size
, &pard
->fd
);
102 ret
= compute_afhi(filename
, pard
->map
, pard
->map_size
,
106 pard
->audio_format_num
= ret
;
107 ret
= -ERRNO_TO_PARA_ERROR(EINVAL
);
108 if (afhi
->chunks_total
== 0)
110 if (PARA_ABS(conf
->begin_chunk_arg
) >= afhi
->chunks_total
)
112 if (conf
->begin_chunk_arg
>= 0)
113 pard
->first_chunk
= conf
->begin_chunk_arg
;
115 pard
->first_chunk
= afhi
->chunks_total
+ conf
->begin_chunk_arg
;
116 if (conf
->end_chunk_given
) {
117 ret
= -ERRNO_TO_PARA_ERROR(EINVAL
);
118 if (PARA_ABS(conf
->end_chunk_arg
) > afhi
->chunks_total
)
120 if (conf
->end_chunk_arg
>= 0)
121 pard
->last_chunk
= conf
->end_chunk_arg
;
123 pard
->last_chunk
= afhi
->chunks_total
+ conf
->end_chunk_arg
;
125 pard
->last_chunk
= afhi
->chunks_total
- 1;
126 ret
= -ERRNO_TO_PARA_ERROR(EINVAL
);
127 if (pard
->first_chunk
>= pard
->last_chunk
)
129 pard
->current_chunk
= pard
->first_chunk
;
130 return pard
->audio_format_num
;
134 para_munmap(pard
->map
, pard
->map_size
);
137 freep(&rn
->private_data
);
141 static void afh_recv_close(struct receiver_node
*rn
)
143 struct private_afh_recv_data
*pard
;
145 if (!rn
|| !rn
->private_data
)
147 pard
= rn
->private_data
;
148 clear_afhi(&pard
->afhi
);
149 para_munmap(pard
->map
, pard
->map_size
);
151 freep(&rn
->private_data
);
154 static void afh_recv_pre_select(struct sched
*s
, struct task
*t
)
156 struct receiver_node
*rn
= container_of(t
, struct receiver_node
, task
);
157 struct private_afh_recv_data
*pard
= rn
->private_data
;
158 struct afh_info
*afhi
= &pard
->afhi
;
159 struct afh_recv_args_info
*conf
= rn
->conf
;
160 struct timeval chunk_time
;
161 int state
= generic_recv_pre_select(s
, t
);
165 if (!conf
->just_in_time_given
) {
169 compute_chunk_time(pard
->current_chunk
- pard
->first_chunk
,
170 &afhi
->chunk_tv
, &pard
->stream_start
, &chunk_time
);
171 sched_request_barrier_or_min_delay(&chunk_time
, s
);
174 static int afh_recv_post_select(__a_unused
struct sched
*s
, struct task
*t
)
176 struct receiver_node
*rn
= container_of(t
, struct receiver_node
, task
);
177 struct afh_recv_args_info
*conf
= rn
->conf
;
178 struct private_afh_recv_data
*pard
= rn
->private_data
;
179 struct btr_node
*btrn
= rn
->btrn
;
180 struct afh_info
*afhi
= &pard
->afhi
;
183 const char *start
, *end
;
185 struct timeval chunk_time
;
187 ret
= btr_node_status(btrn
, 0, BTR_NT_ROOT
);
190 if (pard
->first_chunk
> 0 && !conf
->no_header_given
) {
192 afh_get_header(afhi
, pard
->audio_format_num
, pard
->map
,
193 pard
->map_size
, &header
, &size
);
195 PARA_INFO_LOG("writing header (%zu bytes)\n", size
);
196 buf
= para_malloc(size
);
197 memcpy(buf
, header
, size
);
198 btr_add_output(buf
, size
, btrn
);
199 afh_free_header(header
, pard
->audio_format_num
);
202 if (!conf
->just_in_time_given
) {
203 afh_get_chunk(pard
->first_chunk
, afhi
, pard
->map
, &start
, &size
);
204 afh_get_chunk(pard
->last_chunk
, afhi
, pard
->map
, &end
, &size
);
206 PARA_INFO_LOG("adding %zu bytes\n", end
- start
);
207 btr_add_output_dont_free(start
, end
- start
, btrn
);
211 if (pard
->current_chunk
== pard
->first_chunk
)
212 pard
->stream_start
= *now
;
214 compute_chunk_time(pard
->current_chunk
- pard
->first_chunk
,
215 &afhi
->chunk_tv
, &pard
->stream_start
, &chunk_time
);
216 ret
= tv_diff(&chunk_time
, now
, NULL
);
220 afh_get_chunk(pard
->current_chunk
, afhi
, pard
->map
, &start
, &size
);
221 PARA_DEBUG_LOG("adding chunk %u\n", pard
->current_chunk
);
222 btr_add_output_dont_free(start
, size
, btrn
);
223 if (pard
->current_chunk
>= pard
->last_chunk
) {
227 pard
->current_chunk
++;
231 btr_remove_node(&rn
->btrn
);
232 pard
->current_chunk
= pard
->first_chunk
;
238 * The init function of the afh receiver.
240 * \param r Pointer to the receiver struct to initialize.
242 * This initializes all function pointers of \a r.
244 void afh_recv_init(struct receiver
*r
)
246 struct afh_recv_args_info dummy
;
249 afh_recv_cmdline_parser_init(&dummy
);
250 r
->open
= afh_recv_open
;
251 r
->close
= afh_recv_close
;
252 r
->pre_select
= afh_recv_pre_select
;
253 r
->post_select
= afh_recv_post_select
;
254 r
->parse_config
= afh_recv_parse_config
;
255 r
->free_config
= afh_recv_free_config
;
256 r
->execute
= afh_execute
;
257 r
->help
= (struct ggo_help
)DEFINE_GGO_HELP(afh_recv
);
258 afh_recv_cmdline_parser_free(&dummy
);