daemon: add nice value in service file to improve performance
[platform/upstream/pulseaudio.git] / src / pulsecore / sound-file-stream.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2008 Lennart Poettering
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <errno.h>
29
30 #include <sndfile.h>
31
32 #include <pulse/xmalloc.h>
33 #include <pulse/util.h>
34
35 #include <pulsecore/core-error.h>
36 #include <pulsecore/sink-input.h>
37 #include <pulsecore/log.h>
38 #include <pulsecore/thread-mq.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/mix.h>
41 #include <pulsecore/sndfile-util.h>
42
43 #include "sound-file-stream.h"
44
45 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
46
47 typedef struct file_stream {
48     pa_msgobject parent;
49     pa_core *core;
50     pa_sink_input *sink_input;
51
52     SNDFILE *sndfile;
53     sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames);
54 #ifdef __TIZEN__
55     int32_t repeat;
56 #endif
57
58     /* We need this memblockq here to easily fulfill rewind requests
59      * (even beyond the file start!) */
60     pa_memblockq *memblockq;
61 } file_stream;
62
63 enum {
64     FILE_STREAM_MESSAGE_UNLINK
65 };
66
67 PA_DEFINE_PRIVATE_CLASS(file_stream, pa_msgobject);
68 #define FILE_STREAM(o) (file_stream_cast(o))
69
70 /* Called from main context */
71 static void file_stream_unlink(file_stream *u) {
72     pa_assert(u);
73
74     if (!u->sink_input)
75         return;
76
77     pa_sink_input_unlink(u->sink_input);
78     pa_sink_input_unref(u->sink_input);
79     u->sink_input = NULL;
80
81     /* Make sure we don't decrease the ref count twice. */
82     file_stream_unref(u);
83 }
84
85 /* Called from main context */
86 static void file_stream_free(pa_object *o) {
87     file_stream *u = FILE_STREAM(o);
88     pa_assert(u);
89
90     if (u->memblockq)
91         pa_memblockq_free(u->memblockq);
92
93     if (u->sndfile)
94         sf_close(u->sndfile);
95
96     pa_xfree(u);
97 }
98
99 /* Called from main context */
100 static int file_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
101     file_stream *u = FILE_STREAM(o);
102     file_stream_assert_ref(u);
103
104     switch (code) {
105         case FILE_STREAM_MESSAGE_UNLINK:
106             file_stream_unlink(u);
107             break;
108     }
109
110     return 0;
111 }
112
113 /* Called from main context */
114 static void sink_input_kill_cb(pa_sink_input *i) {
115     file_stream *u;
116
117     pa_sink_input_assert_ref(i);
118     u = FILE_STREAM(i->userdata);
119     file_stream_assert_ref(u);
120
121     file_stream_unlink(u);
122 }
123
124 /* Called from IO thread context */
125 static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t state) {
126     file_stream *u;
127
128     pa_sink_input_assert_ref(i);
129     u = FILE_STREAM(i->userdata);
130     file_stream_assert_ref(u);
131
132     /* If we are added for the first time, ask for a rewinding so that
133      * we are heard right-away. */
134     if (PA_SINK_INPUT_IS_LINKED(state) &&
135         i->thread_info.state == PA_SINK_INPUT_INIT && i->sink)
136         pa_sink_input_request_rewind(i, 0, false, true, true);
137 }
138
139 /* Called from IO thread context */
140 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
141     file_stream *u;
142
143     pa_sink_input_assert_ref(i);
144     pa_assert(chunk);
145     u = FILE_STREAM(i->userdata);
146     file_stream_assert_ref(u);
147
148     if (!u->memblockq)
149         return -1;
150
151     for (;;) {
152         pa_memchunk tchunk;
153         size_t fs;
154         void *p;
155         sf_count_t n;
156
157         if (pa_memblockq_peek(u->memblockq, chunk) >= 0) {
158             chunk->length = PA_MIN(chunk->length, length);
159             pa_memblockq_drop(u->memblockq, chunk->length);
160             return 0;
161         }
162
163         if (!u->sndfile)
164             break;
165
166         tchunk.memblock = pa_memblock_new(i->sink->core->mempool, length);
167         tchunk.index = 0;
168
169         p = pa_memblock_acquire(tchunk.memblock);
170
171         if (u->readf_function) {
172             fs = pa_frame_size(&i->sample_spec);
173             n = u->readf_function(u->sndfile, p, (sf_count_t) (length/fs));
174         } else {
175             fs = 1;
176             n = sf_read_raw(u->sndfile, p, (sf_count_t) length);
177         }
178
179         pa_memblock_release(tchunk.memblock);
180
181         if (n <= 0) {
182 #ifdef __TIZEN__
183             if (u->repeat == -1 || --u->repeat > 0) {
184                 sf_seek(u->sndfile, 0, SEEK_SET);
185                 pa_memblock_unref(tchunk.memblock);
186                 continue;
187             }
188 #endif
189             pa_memblock_unref(tchunk.memblock);
190
191             sf_close(u->sndfile);
192             u->sndfile = NULL;
193             break;
194         }
195
196         tchunk.length = (size_t) n * fs;
197
198 #ifdef __TIZEN__
199         /* check invalid sample size */
200         if (PA_UNLIKELY(tchunk.length % pa_frame_size(&i->sample_spec))) {
201             pa_log_warn("Dropped not aligned samples. length(%zu), fs(%zu)",
202                                 tchunk.length, pa_frame_size(&i->sample_spec));
203             tchunk.length = PA_ROUND_DOWN(n, pa_frame_size(&i->sample_spec));
204             if (tchunk.length == 0) {
205                  pa_memblock_unref(tchunk.memblock);
206                  continue;
207             }
208         }
209 #endif
210
211         pa_memblockq_push(u->memblockq, &tchunk);
212         pa_memblock_unref(tchunk.memblock);
213     }
214
215     if (pa_sink_input_safe_to_remove(i)) {
216         pa_memblockq_free(u->memblockq);
217         u->memblockq = NULL;
218
219         pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), FILE_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL);
220     }
221
222     return -1;
223 }
224
225 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
226     file_stream *u;
227
228     pa_sink_input_assert_ref(i);
229     u = FILE_STREAM(i->userdata);
230     file_stream_assert_ref(u);
231
232     if (!u->memblockq)
233         return;
234
235     pa_memblockq_rewind(u->memblockq, nbytes);
236 }
237
238 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
239     file_stream *u;
240
241     pa_sink_input_assert_ref(i);
242     u = FILE_STREAM(i->userdata);
243     file_stream_assert_ref(u);
244
245     if (!u->memblockq)
246         return;
247
248     pa_memblockq_set_maxrewind(u->memblockq, nbytes);
249 }
250
251 int pa_play_file(
252         pa_sink *sink,
253         const char *fname,
254         const pa_cvolume *volume) {
255
256     file_stream *u = NULL;
257     pa_sample_spec ss;
258     pa_channel_map cm;
259     pa_sink_input_new_data data;
260     int fd;
261     SF_INFO sfi;
262     pa_memchunk silence;
263
264     pa_assert(sink);
265     pa_assert(fname);
266
267     u = pa_msgobject_new(file_stream);
268     u->parent.parent.free = file_stream_free;
269     u->parent.process_msg = file_stream_process_msg;
270     u->core = sink->core;
271     u->sink_input = NULL;
272     u->sndfile = NULL;
273     u->readf_function = NULL;
274     u->memblockq = NULL;
275
276     if ((fd = pa_open_cloexec(fname, O_RDONLY, 0)) < 0) {
277         pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno));
278         goto fail;
279     }
280
281     /* FIXME: For now we just use posix_fadvise to avoid page faults
282      * when accessing the file data. Eventually we should move the
283      * file reader into the main event loop and pass the data over the
284      * asyncmsgq. */
285
286 #ifdef HAVE_POSIX_FADVISE
287     if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) {
288         pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno));
289         goto fail;
290     } else
291         pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded.");
292
293     if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED) < 0) {
294         pa_log_warn("POSIX_FADV_WILLNEED failed: %s", pa_cstrerror(errno));
295         goto fail;
296     } else
297         pa_log_debug("POSIX_FADV_WILLNEED succeeded.");
298 #endif
299
300     pa_zero(sfi);
301     if (!(u->sndfile = sf_open_fd(fd, SFM_READ, &sfi, 1))) {
302         pa_log("Failed to open file %s", fname);
303 #ifdef __TIZEN__
304         fd = -1;
305 #endif
306         goto fail;
307     }
308
309     fd = -1;
310
311     if (pa_sndfile_read_sample_spec(u->sndfile, &ss) < 0) {
312         pa_log("Failed to determine file sample format.");
313         goto fail;
314     }
315
316     if (pa_sndfile_read_channel_map(u->sndfile, &cm) < 0) {
317         if (ss.channels > 2)
318             pa_log_info("Failed to determine file channel map, synthesizing one.");
319         pa_channel_map_init_extend(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT);
320     }
321
322     u->readf_function = pa_sndfile_readf_function(&ss);
323
324     pa_sink_input_new_data_init(&data);
325     pa_sink_input_new_data_set_sink(&data, sink, false, true);
326     data.driver = __FILE__;
327     pa_sink_input_new_data_set_sample_spec(&data, &ss);
328     pa_sink_input_new_data_set_channel_map(&data, &cm);
329     pa_sink_input_new_data_set_volume(&data, volume);
330     pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, pa_path_get_filename(fname));
331     pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname);
332     pa_sndfile_init_proplist(u->sndfile, data.proplist);
333
334     pa_sink_input_new(&u->sink_input, sink->core, &data);
335     pa_sink_input_new_data_done(&data);
336
337     if (!u->sink_input)
338         goto fail;
339
340     u->sink_input->pop = sink_input_pop_cb;
341     u->sink_input->process_rewind = sink_input_process_rewind_cb;
342     u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
343     u->sink_input->kill = sink_input_kill_cb;
344     u->sink_input->state_change = sink_input_state_change_cb;
345     u->sink_input->userdata = u;
346
347     pa_sink_input_get_silence(u->sink_input, &silence);
348     u->memblockq = pa_memblockq_new("sound-file-stream memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &silence);
349     pa_memblock_unref(silence.memblock);
350
351     pa_sink_input_put(u->sink_input);
352
353     /* The reference to u is dangling here, because we want to keep
354      * this stream around until it is fully played. */
355
356     return 0;
357
358 fail:
359     file_stream_unref(u);
360
361     if (fd >= 0)
362         pa_close(fd);
363
364     return -1;
365 }
366
367 #ifdef __TIZEN__
368 int pa_play_file_repeat(
369         pa_sink *sink,
370         const char *fname,
371         const pa_cvolume *volume,
372         pa_proplist *p,
373         uint32_t repeat,
374         int fd,
375         uint32_t *stream_idx) {
376
377     file_stream *u = NULL;
378     pa_sample_spec ss;
379     pa_channel_map cm;
380     pa_sink_input_new_data data;
381     SF_INFO sfi;
382     pa_memchunk silence;
383
384     pa_assert(sink);
385     pa_assert(fname);
386
387     u = pa_msgobject_new(file_stream);
388     u->parent.parent.free = file_stream_free;
389     u->parent.process_msg = file_stream_process_msg;
390     u->core = sink->core;
391     u->sink_input = NULL;
392     u->sndfile = NULL;
393     u->readf_function = NULL;
394     u->memblockq = NULL;
395     u->repeat = (repeat == 0) ? -1 : (int32_t)repeat;
396
397     if (fd == -1) {
398         if ((fd = pa_open_cloexec(fname, O_RDONLY, 0)) < 0) {
399             pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno));
400             goto fail;
401         }
402     }
403
404     /* FIXME: For now we just use posix_fadvise to avoid page faults
405      * when accessing the file data. Eventually we should move the
406      * file reader into the main event loop and pass the data over the
407      * asyncmsgq. */
408
409 #ifdef HAVE_POSIX_FADVISE
410     if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) {
411         pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno));
412         goto fail;
413     } else
414         pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded.");
415
416     if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED) < 0) {
417         pa_log_warn("POSIX_FADV_WILLNEED failed: %s", pa_cstrerror(errno));
418         goto fail;
419     } else
420         pa_log_debug("POSIX_FADV_WILLNEED succeeded.");
421 #endif
422
423     pa_zero(sfi);
424     if (!(u->sndfile = sf_open_fd(fd, SFM_READ, &sfi, 1))) {
425         pa_log("Failed to open file %s", fname);
426 #ifdef __TIZEN__
427         fd = -1;
428 #endif
429         goto fail;
430     }
431
432     fd = -1;
433
434     if (pa_sndfile_read_sample_spec(u->sndfile, &ss) < 0) {
435         pa_log("Failed to determine file sample format.");
436         goto fail;
437     }
438
439     if (pa_sndfile_read_channel_map(u->sndfile, &cm) < 0) {
440         if (ss.channels > 2)
441             pa_log_info("Failed to determine file channel map, synthesizing one.");
442         pa_channel_map_init_extend(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT);
443     }
444
445     u->readf_function = pa_sndfile_readf_function(&ss);
446
447     pa_sink_input_new_data_init(&data);
448     pa_sink_input_new_data_set_sink(&data, sink, false, true);
449     data.driver = __FILE__;
450     pa_sink_input_new_data_set_sample_spec(&data, &ss);
451     pa_sink_input_new_data_set_channel_map(&data, &cm);
452     pa_sink_input_new_data_set_volume(&data, volume);
453     pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, pa_path_get_filename(fname));
454     pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname);
455     pa_proplist_update(data.proplist, PA_UPDATE_MERGE, p);
456     pa_sndfile_init_proplist(u->sndfile, data.proplist);
457
458     pa_sink_input_new(&u->sink_input, sink->core, &data);
459     pa_sink_input_new_data_done(&data);
460
461     if (!u->sink_input)
462         goto fail;
463
464     u->sink_input->pop = sink_input_pop_cb;
465     u->sink_input->process_rewind = sink_input_process_rewind_cb;
466     u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
467     u->sink_input->kill = sink_input_kill_cb;
468     u->sink_input->state_change = sink_input_state_change_cb;
469     u->sink_input->userdata = u;
470
471     pa_sink_input_get_silence(u->sink_input, &silence);
472     u->memblockq = pa_memblockq_new("sound-file-stream memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &silence);
473     pa_memblock_unref(silence.memblock);
474
475     pa_sink_input_put(u->sink_input);
476     *stream_idx = u->sink_input->index;
477
478     /* The reference to u is dangling here, because we want to keep
479      * this stream around until it is fully played. */
480
481     return 0;
482
483 fail:
484     file_stream_unref(u);
485
486     if (fd >= 0)
487         pa_close(fd);
488
489     return -1;
490 }
491 #endif