pulsecore: Adds pa_play_file_repeat function 93/228893/5 submit/tizen/20200403.080755 submit/tizen/20200406.030837 submit/tizen/20200407.002130
authorJaechul Lee <jcsing.lee@samsung.com>
Thu, 26 Mar 2020 07:54:58 +0000 (16:54 +0900)
committerJaechul Lee <jcsing.lee@samsung.com>
Fri, 3 Apr 2020 00:33:54 +0000 (09:33 +0900)
[Version] 13.0-4
[Issue Type] None

Change-Id: I704a7aa9e8fd871f47af3988b8c2997ed293692f
Signed-off-by: Jaechul Lee <jcsing.lee@samsung.com>
packaging/pulseaudio.spec
src/pulsecore/sound-file-stream.c

index d51b9ab..e688e91 100644 (file)
@@ -3,7 +3,7 @@
 Name:             pulseaudio
 Summary:          Improved Linux sound server
 Version:          13.0
-Release:          3
+Release:          4
 Group:            Multimedia/Audio
 License:          LGPL-2.1
 URL:              http://pulseaudio.org
index 147aa22..bda0cab 100644 (file)
@@ -51,6 +51,9 @@ typedef struct file_stream {
 
     SNDFILE *sndfile;
     sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames);
+#ifdef __TIZEN__
+    int32_t repeat;
+#endif
 
     /* We need this memblockq here to easily fulfill rewind requests
      * (even beyond the file start!) */
@@ -176,6 +179,12 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk
         pa_memblock_release(tchunk.memblock);
 
         if (n <= 0) {
+#ifdef __TIZEN__
+            if (u->repeat == -1 || --u->repeat > 0) {
+                sf_seek(u->sndfile, 0, SEEK_SET);
+                continue;
+            }
+#endif
             pa_memblock_unref(tchunk.memblock);
 
             sf_close(u->sndfile);
@@ -337,3 +346,124 @@ fail:
 
     return -1;
 }
+
+#ifdef __TIZEN__
+int pa_play_file_repeat(
+        pa_sink *sink,
+        const char *fname,
+        const pa_cvolume *volume,
+        pa_proplist *p,
+        uint32_t repeat,
+        uint32_t *stream_idx) {
+
+    file_stream *u = NULL;
+    pa_sample_spec ss;
+    pa_channel_map cm;
+    pa_sink_input_new_data data;
+    int fd;
+    SF_INFO sfi;
+    pa_memchunk silence;
+
+    pa_assert(sink);
+    pa_assert(fname);
+
+    u = pa_msgobject_new(file_stream);
+    u->parent.parent.free = file_stream_free;
+    u->parent.process_msg = file_stream_process_msg;
+    u->core = sink->core;
+    u->sink_input = NULL;
+    u->sndfile = NULL;
+    u->readf_function = NULL;
+    u->memblockq = NULL;
+    u->repeat = (repeat == 0) ? -1 : repeat;
+
+    if ((fd = pa_open_cloexec(fname, O_RDONLY, 0)) < 0) {
+        pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno));
+        goto fail;
+    }
+
+    /* FIXME: For now we just use posix_fadvise to avoid page faults
+     * when accessing the file data. Eventually we should move the
+     * file reader into the main event loop and pass the data over the
+     * asyncmsgq. */
+
+#ifdef HAVE_POSIX_FADVISE
+    if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) {
+        pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno));
+        goto fail;
+    } else
+        pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded.");
+
+    if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED) < 0) {
+        pa_log_warn("POSIX_FADV_WILLNEED failed: %s", pa_cstrerror(errno));
+        goto fail;
+    } else
+        pa_log_debug("POSIX_FADV_WILLNEED succeeded.");
+#endif
+
+    pa_zero(sfi);
+    if (!(u->sndfile = sf_open_fd(fd, SFM_READ, &sfi, 1))) {
+        pa_log("Failed to open file %s", fname);
+        goto fail;
+    }
+
+    fd = -1;
+
+    if (pa_sndfile_read_sample_spec(u->sndfile, &ss) < 0) {
+        pa_log("Failed to determine file sample format.");
+        goto fail;
+    }
+
+    if (pa_sndfile_read_channel_map(u->sndfile, &cm) < 0) {
+        if (ss.channels > 2)
+            pa_log_info("Failed to determine file channel map, synthesizing one.");
+        pa_channel_map_init_extend(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT);
+    }
+
+    u->readf_function = pa_sndfile_readf_function(&ss);
+
+    pa_sink_input_new_data_init(&data);
+    pa_sink_input_new_data_set_sink(&data, sink, false, true);
+    data.driver = __FILE__;
+    pa_sink_input_new_data_set_sample_spec(&data, &ss);
+    pa_sink_input_new_data_set_channel_map(&data, &cm);
+    pa_sink_input_new_data_set_volume(&data, volume);
+    pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, pa_path_get_filename(fname));
+    pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname);
+    pa_proplist_update(data.proplist, PA_UPDATE_MERGE, p);
+    pa_sndfile_init_proplist(u->sndfile, data.proplist);
+
+    pa_sink_input_new(&u->sink_input, sink->core, &data);
+    pa_sink_input_new_data_done(&data);
+
+    if (!u->sink_input)
+        goto fail;
+
+    u->sink_input->pop = sink_input_pop_cb;
+    u->sink_input->process_rewind = sink_input_process_rewind_cb;
+    u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
+    u->sink_input->kill = sink_input_kill_cb;
+    u->sink_input->state_change = sink_input_state_change_cb;
+    u->sink_input->userdata = u;
+
+    pa_sink_input_get_silence(u->sink_input, &silence);
+    u->memblockq = pa_memblockq_new("sound-file-stream memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &silence);
+    pa_memblock_unref(silence.memblock);
+
+    pa_sink_input_put(u->sink_input);
+    *stream_idx = u->sink_input->index;
+
+    /* The reference to u is dangling here, because we want to keep
+     * this stream around until it is fully played. */
+
+    return 0;
+
+fail:
+    file_stream_unref(u);
+
+    if (fd >= 0)
+        pa_close(fd);
+
+    return -1;
+}
+#endif