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!) */
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);
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