1 // pulse.c
2 // LiVES (lives-exe)
3 // (c) G. Finch <salsaman+lives@gmail.com> 2005 - 2020
4 // Released under the GPL 3 or later
5 // see file ../COPYING for licensing details
6 
7 #ifdef HAVE_PULSE_AUDIO
8 #include "main.h"
9 #include "callbacks.h"
10 #include "effects.h"
11 #include "effects-weed.h"
12 
13 #define afile mainw->files[pulsed->playing_file]
14 
15 //#define DEBUG_PULSE
16 
17 #define THRESH_BASE 10000.
18 #define THRESH_MAX 50000.
19 
20 static pulse_driver_t pulsed;
21 static pulse_driver_t pulsed_reader;
22 
23 static pa_threaded_mainloop *pa_mloop = NULL;
24 static pa_context *pcon = NULL;
25 static char pactxnm[512];
26 
27 static uint32_t pulse_server_rate = 0;
28 
29 #define PULSE_READ_BYTES 48000
30 
31 static uint8_t prbuf[PULSE_READ_BYTES * 2];
32 
33 static size_t prb = 0;
34 
35 static boolean seek_err;
36 static boolean sync_ready = FALSE;
37 
38 static volatile int lock_count = 0;
39 
40 static off_t fwd_seek_pos = 0;
41 
42 ///////////////////////////////////////////////////////////////////
43 
44 
pa_mloop_lock(void)45 LIVES_GLOBAL_INLINE void pa_mloop_lock(void) {
46   if (!pa_threaded_mainloop_in_thread(pa_mloop)) {
47     pa_threaded_mainloop_lock(pa_mloop);
48     ++lock_count;
49   } else {
50     LIVES_ERROR("tried to lock pa mainloop within audio thread");
51   }
52 }
53 
pa_mloop_unlock(void)54 LIVES_GLOBAL_INLINE void pa_mloop_unlock(void) {
55   if (!pa_threaded_mainloop_in_thread(pa_mloop)) {
56     if (lock_count > 0) {
57       --lock_count;
58       pa_threaded_mainloop_unlock(pa_mloop);
59     }
60   } else {
61     LIVES_ERROR("tried to unlock pa mainloop within audio thread");
62   }
63 }
64 
65 
pulse_server_cb(pa_context * c,const pa_server_info * info,void * userdata)66 static void pulse_server_cb(pa_context *c, const pa_server_info *info, void *userdata) {
67   if (!info) pulse_server_rate = 0;
68   else pulse_server_rate = info->sample_spec.rate;
69   pa_threaded_mainloop_signal(pa_mloop, 0);
70 }
71 
pulse_success_cb(pa_stream * stream,int i,void * userdata)72 static void pulse_success_cb(pa_stream *stream, int i, void *userdata) {pa_threaded_mainloop_signal(pa_mloop, 0);}
73 
74 #include <sys/time.h>
75 #include <sys/resource.h>
76 
stream_underflow_callback(pa_stream * s,void * userdata)77 static void stream_underflow_callback(pa_stream *s, void *userdata) {
78   // we get isolated cases when the GUI is very busy, for example right after playback
79   // we should ignore these isolated cases, except in DEBUG mode.
80   // otherwise - increase tlen and possibly maxlen ?
81   // e.g. pa_stream_set_buffer_attr(s, battr, success_cb, NULL);
82 
83   if (prefs->show_dev_opts) {
84     fprintf(stderr, "PA Stream underrun.\n");
85   }
86 
87   mainw->uflow_count++;
88 }
89 
90 
stream_overflow_callback(pa_stream * s,void * userdata)91 static void stream_overflow_callback(pa_stream *s, void *userdata) {
92   pa_operation *paop;
93   //pulse_driver_t *pulsed = (pulse_driver_t *)userdata;
94   fprintf(stderr, "Stream overrun.\n");
95   paop = pa_stream_flush(s, NULL, NULL);
96   pa_operation_unref(paop);
97   //break_me();
98 }
99 
100 
stream_moved_callback(pa_stream * s,void * userdata)101 static void stream_moved_callback(pa_stream *s, void *userdata) {
102   //pulse_driver_t *pulsed = (pulse_driver_t *)userdata;
103   fprintf(stderr, "Stream moved. \n");
104 }
105 
106 
stream_buffer_attr_callback(pa_stream * s,void * userdata)107 static void stream_buffer_attr_callback(pa_stream *s, void *userdata) {
108   //fprintf(stderr, "Stream ba changed. \n");
109 }
110 
111 
lives_pulse_init(short startup_phase)112 boolean lives_pulse_init(short startup_phase) {
113   // startup pulseaudio server
114   char *msg;
115   pa_context_state_t pa_state;
116   ticks_t timeout;
117   lives_alarm_t alarm_handle;
118   LiVESResponseType resp;
119   boolean retried = FALSE;
120 
121   if (pa_mloop) return TRUE;
122 
123 retry:
124 
125   pa_mloop = pa_threaded_mainloop_new();
126   lives_snprintf(pactxnm, 512, "LiVES-%"PRId64, lives_random());
127   pcon = pa_context_new(pa_threaded_mainloop_get_api(pa_mloop), pactxnm);
128   pa_context_connect(pcon, NULL, (pa_context_flags_t)0, NULL);
129   pa_threaded_mainloop_start(pa_mloop);
130 
131   pa_state = pa_context_get_state(pcon);
132 
133   alarm_handle = lives_alarm_set(LIVES_SHORT_TIMEOUT);
134   while ((timeout = lives_alarm_check(alarm_handle)) > 0 && pa_state != PA_CONTEXT_READY) {
135     sched_yield();
136     lives_usleep(prefs->sleep_time);
137     pa_state = pa_context_get_state(pcon);
138   }
139   lives_alarm_clear(alarm_handle);
140 
141   if (pa_context_get_state(pcon) == PA_CONTEXT_READY) timeout = 1;
142 
143   if (timeout == 0) {
144     pa_context_unref(pcon);
145     pcon = NULL;
146     pulse_shutdown();
147     if (!retried) {
148       retried = TRUE;
149       goto retry;
150     }
151     LIVES_WARN("Unable to connect to the pulseaudio server");
152 
153     if (!mainw->foreign) {
154       if (startup_phase != 2) {
155         resp = do_abort_cancel_retry_dialog(
156                  _("\nUnable to connect to the pulseaudio server.\n"
157                    "Click Abort to exit from LiVES, Retry to try again,\n"
158                    "or Cancel to run LiVES without audio features.\n"
159                    "Audio settings can be updated in Tools/Preferences/Playback.\n"));
160         if (resp == LIVES_RESPONSE_RETRY) {
161           fprintf(stderr, "Retrying...\n");
162           goto retry;
163         }
164         fprintf(stderr, "Giving up.\n");
165         switch_aud_to_none(TRUE);
166       } else {
167         msg = (_("\nUnable to connect to the pulseaudio server.\n"));
168         if (startup_phase != 2) {
169           do_error_dialog(msg);
170           mainw->aplayer_broken = TRUE;
171         } else {
172           do_error_dialogf("%s%s", msg, _("LiVES will exit and you can choose another audio player.\n"));
173         }
174         lives_free(msg);
175       }
176     }
177     return FALSE;
178   }
179   return TRUE;
180 }
181 
182 
pulse_get_rec_avals(pulse_driver_t * pulsed)183 void pulse_get_rec_avals(pulse_driver_t *pulsed) {
184   mainw->rec_aclip = pulsed->playing_file;
185   if (mainw->rec_aclip != -1) {
186     mainw->rec_aseek = fabs((double)(fwd_seek_pos / (double)(afile->achans * afile->asampsize / 8)) / (double)afile->arps)
187                        + (double)(mainw->startticks - mainw->currticks) / TICKS_PER_SECOND_DBL;
188     mainw->rec_avel = fabs((double)pulsed->in_arate / (double)afile->arps) * (double)afile->adirection;
189     //g_print("RECSEEK is %f %ld\n", mainw->rec_aseek, pulsed->real_seek_pos);
190   }
191 }
192 
193 
pulse_set_rec_avals(pulse_driver_t * pulsed)194 static void pulse_set_rec_avals(pulse_driver_t *pulsed) {
195   // record direction change (internal)
196   mainw->rec_aclip = pulsed->playing_file;
197   if (mainw->rec_aclip != -1) {
198     pulse_get_rec_avals(pulsed);
199   }
200 }
201 
202 
pulse_get_buffsize(pulse_driver_t * pulsed)203 LIVES_GLOBAL_INLINE size_t pulse_get_buffsize(pulse_driver_t *pulsed) {return pulsed->chunk_size;}
204 
205 #if !HAVE_PA_STREAM_BEGIN_WRITE
pulse_buff_free(void * ptr)206 static void pulse_buff_free(void *ptr) {lives_free(ptr);}
207 #endif
208 
sync_ready_ok(pulse_driver_t * pulsed,size_t nbytes)209 static void sync_ready_ok(pulse_driver_t *pulsed, size_t nbytes) {
210   if (nbytes >= 8192) {
211     mainw->syncticks += ((double)nbytes / (double)(pulsed->out_arate) * 1000000.
212                          / (double)(pulsed->out_achans * pulsed->out_asamps >> 3) + .5) * USEC_TO_TICKS;
213   } else {
214     mainw->startticks = mainw->currticks = lives_get_current_playback_ticks(mainw->origsecs, mainw->orignsecs, NULL);
215   }
216   mainw->fps_mini_measure = 0;
217   mainw->fps_mini_ticks = mainw->currticks;
218   pthread_mutex_lock(&mainw->avseek_mutex);
219   mainw->audio_seek_ready = TRUE;
220   pthread_cond_signal(&mainw->avseek_cond);
221   pthread_mutex_unlock(&mainw->avseek_mutex);
222 }
223 
224 
sample_silence_pulse(pulse_driver_t * pulsed,size_t nbytes,size_t xbytes)225 static void sample_silence_pulse(pulse_driver_t *pulsed, size_t nbytes, size_t xbytes) {
226   uint8_t *buff;
227   int nsamples;
228 
229   if (sync_ready) sync_ready_ok(pulsed, xbytes > 0 ? xbytes : 0);
230 
231   if (xbytes <= 0) return;
232   if (mainw->aplayer_broken) return;
233   while (nbytes > 0) {
234     int ret = 0;
235 #if HAVE_PA_STREAM_BEGIN_WRITE
236     xbytes = -1;
237     // returns a buffer and size for us to write to
238     pa_stream_begin_write(pulsed->pstream, (void **)&buff, &xbytes);
239 #endif
240     if (nbytes < xbytes) xbytes = nbytes;
241 #if !HAVE_PA_STREAM_BEGIN_WRITE
242     buff = (uint8_t *)lives_calloc(xbytes);
243 #endif
244     if (!buff || ret != 0) return;
245 
246 #if HAVE_PA_STREAM_BEGIN_WRITE
247     lives_memset(buff, 0, xbytes);
248 #endif
249     if (pulsed->astream_fd != -1) audio_stream(buff, xbytes, pulsed->astream_fd); // old streaming API
250 
251     nsamples = xbytes / pulsed->out_achans / (pulsed->out_asamps >> 3);
252 
253     // streaming API
254     if (mainw->ext_audio && mainw->vpp && mainw->vpp->render_audio_frame_float && pulsed->playing_file != -1
255         && pulsed->playing_file != mainw->ascrap_file) {
256       sample_silence_stream(pulsed->out_achans, nsamples);
257     }
258 
259     if (mainw->audio_frame_buffer && prefs->audio_src != AUDIO_SRC_EXT
260         && (!mainw->event_list || mainw->record || mainw->record_paused))  {
261       // buffer audio for any generators
262       // interleaved, so we paste all to channel 0
263       append_to_audio_buffer16(buff, nsamples * pulsed->out_achans, 0);
264       mainw->audio_frame_buffer->samples_filled += nsamples * pulsed->out_achans;
265     }
266 #if !HAVE_PA_STREAM_BEGIN_WRITE
267     pa_stream_write(pulsed->pstream, buff, xbytes, pulse_buff_free, 0, PA_SEEK_RELATIVE);
268 #else
269     pa_stream_write(pulsed->pstream, buff, xbytes, NULL, 0, PA_SEEK_RELATIVE);
270 #endif
271     nbytes -= xbytes;
272     if (!pulsed->is_paused) pulsed->frames_written += nsamples;
273     pulsed->extrausec += ((double)xbytes / (double)(pulsed->out_arate) * 1000000.
274                           / (double)(pulsed->out_achans * pulsed->out_asamps >> 3) + .5);
275   }
276   pulsed->real_seek_pos = pulsed->seek_pos;
277   if (IS_VALID_CLIP(pulsed->playing_file) && pulsed->seek_pos < afile->afilesize)
278     afile->aseek_pos = pulsed->seek_pos;
279 }
280 
281 
282 #define NBYTES_LIMIT (65536 * 4)
283 
284 static short *shortbuffer = NULL;
285 
286 /**
287    @brief write audio to pulse
288 
289    PULSE AUDIO calls this periodically to get the next audio buffer
290    note the buffer size can, and does, change on each call, making it inefficient to use ringbuffers
291 
292    there are three main modes of operation (plus silence)
293    - playing back from a file; in this case we keep track of the seek position so we know when we hit a boundary
294    -- would probably better to have another thread cache the audio like the jack player does, currently we just read from
295    the audio file (using buffered reads would be not really help since we also play in reverse) and in addition the buffer size
296    is not constant
297 
298    - playing from a memory buffer; this mode is used in multitrack or when reproducing a recording (event_list);
299    since the audio composition is known in advance it is possible to prepare audio blocks, apply effects and volume mixer levels
300    in advance
301 
302    - playing from an audio generator; we just run the plugin and request the correct number of samples.
303 
304    we also resample / change formats as needed.
305 
306    currently we don't support end to end float, but that is planned for the very near future.
307 
308    During playback we always send audio, even if it is silence, since the video timings may be derived from the
309    audio sample count.
310 */
pulse_audio_write_process(pa_stream * pstream,size_t nbytes,void * arg)311 static void pulse_audio_write_process(pa_stream *pstream, size_t nbytes, void *arg) {
312   pulse_driver_t *pulsed = (pulse_driver_t *)arg;
313   pa_operation *paop;
314   aserver_message_t *msg;
315   ssize_t pad_bytes = 0;
316   uint8_t *buffer;
317   uint64_t nsamples = nbytes / pulsed->out_achans / (pulsed->out_asamps >> 3);
318   off_t offs = 0;
319   size_t xbytes = pa_stream_writable_size(pstream);
320   off_t seek, xseek;
321   pa_volume_t pavol;
322   char *filename;
323 
324   boolean got_cmd = FALSE;
325   boolean from_memory = FALSE;
326   boolean needs_free = FALSE;
327 
328   int new_file;
329 
330   sync_ready = FALSE;
331 
332   //pa_thread_make_realtime(50);
333   //g_print("PA\n");
334   pulsed->real_seek_pos = pulsed->seek_pos;
335   pulsed->pstream = pstream;
336 
337   if (xbytes > nbytes) xbytes = nbytes;
338 
339   if (!mainw->is_ready || !pulsed || (!LIVES_IS_PLAYING && !pulsed->msgq) || nbytes > NBYTES_LIMIT) {
340     sample_silence_pulse(pulsed, nsamples * pulsed->out_achans * (pulsed->out_asamps >> 3), xbytes);
341     //g_print("pt a1 %ld %d %p %d %p %ld\n",nsamples, mainw->is_ready, pulsed, mainw->playing_file, pulsed->msgq, nbytes);
342     return;
343   }
344 
345   /// handle control commands from the main (video) thread
346   if ((msg = (aserver_message_t *)pulsed->msgq) != NULL) {
347     got_cmd = TRUE;
348     switch (msg->command) {
349     case ASERVER_CMD_FILE_OPEN:
350       pulsed->in_use = TRUE;
351       paop = pa_stream_flush(pulsed->pstream, NULL, NULL);
352       pa_operation_unref(paop);
353       new_file = atoi((char *)msg->data);
354       if (pulsed->playing_file != new_file) {
355         filename = lives_get_audio_file_name(new_file);
356         pulsed->fd = lives_open_buffered_rdonly(filename);
357         if (pulsed->fd == -1) {
358           // dont show gui errors - we are running in realtime thread
359           LIVES_ERROR("pulsed: error opening");
360           LIVES_ERROR(filename);
361           pulsed->playing_file = -1;
362         }
363         lives_free(filename);
364       }
365       pulsed->real_seek_pos = pulsed->seek_pos = 0;
366       pulsed->playing_file = new_file;
367       //pa_stream_trigger(pulsed->pstream, NULL, NULL); // only needed for prebuffer
368       break;
369     case ASERVER_CMD_FILE_CLOSE:
370       pulsed->in_use = TRUE;
371       paop = pa_stream_flush(pulsed->pstream, NULL, NULL);
372       pa_operation_unref(paop);
373       if (pulsed->fd >= 0) lives_close_buffered(pulsed->fd);
374       if (pulsed->sound_buffer == pulsed->aPlayPtr->data) pulsed->sound_buffer = NULL;
375       if (pulsed->aPlayPtr->data) {
376         lives_free((void *)(pulsed->aPlayPtr->data));
377         pulsed->aPlayPtr->data = NULL;
378       }
379       pulsed->aPlayPtr->max_size = pulsed->aPlayPtr->size = 0;
380       pulsed->fd = pulsed->playing_file = -1;
381       pulsed->in_use = FALSE;
382       pulsed->seek_pos = pulsed->real_seek_pos = fwd_seek_pos = 0;
383       break;
384     case ASERVER_CMD_FILE_SEEK:
385       if (pulsed->fd < 0) break;
386       pulsed->in_use = TRUE;
387       paop = pa_stream_flush(pulsed->pstream, NULL, NULL);
388       pa_operation_unref(paop);
389       xseek = seek = atol((char *)msg->data);
390       /// when we get a seek request, here is what we will do:
391       /// - any time a video seek is requested, video_seek_ready and audio_seek_ready are both set to FALSE
392       /// - once the video player is about to show a frame, it will set video_seek_ready, and cond_mutex wait
393       /// - if (volatile) video_seek_ready is FALSE:
394       /// -- seek to the point
395       /// -- play silence until video_seek_ready is TRUE
396       /// - once video_seek_ready is TRUE, adjust by delta time, prefill the buffer
397       ///   and cond_mutex_signal so video can continue
398 
399       //g_print("xseek is %ld\n", xseek);
400       if (seek < 0.) xseek = 0.;
401       xseek = ALIGN_CEIL64(xseek, afile->achans * (afile->asampsize >> 3));
402       lives_lseek_buffered_rdonly_absolute(pulsed->fd, xseek);
403       pulsed->real_seek_pos = pulsed->seek_pos = afile->aseek_pos = xseek;
404       if (pulsed->playing_file == mainw->ascrap_file || afile->adirection == LIVES_DIRECTION_FORWARD) {
405         lives_buffered_rdonly_set_reversed(pulsed->fd, FALSE);
406       } else {
407         lives_buffered_rdonly_set_reversed(pulsed->fd, TRUE);
408       }
409       break;
410     default:
411       pulsed->msgq = NULL;
412       msg->data = NULL;
413     }
414     if (msg->next != msg) lives_freep((void **) & (msg->data));
415     msg->command = ASERVER_CMD_PROCESSED;
416     pulsed->msgq = msg->next;
417     if (pulsed->msgq && pulsed->msgq->next == pulsed->msgq) pulsed->msgq->next = NULL;
418   }
419   if (got_cmd) {
420     sample_silence_pulse(pulsed, nsamples * pulsed->out_achans * (pulsed->out_asamps >> 3), xbytes);
421     return;
422   }
423 
424   /// this is the value we will return from pulse_get_rec_avals
425   fwd_seek_pos = pulsed->real_seek_pos;
426 
427   if (pulsed->chunk_size != nbytes) pulsed->chunk_size = nbytes;
428 
429   pulsed->state = pa_stream_get_state(pulsed->pstream);
430 
431   if (pulsed->state == PA_STREAM_READY) {
432     uint64_t pulseFramesAvailable = nsamples;
433     uint64_t inputFramesAvailable = 0;
434     uint64_t numFramesToWrite = 0;
435     double in_framesd = 0.;
436     float clip_vol = 1.;
437 #ifdef DEBUG_PULSE
438     int64_t in_frames = 0;
439 #endif
440     size_t in_bytes = 0, xin_bytes = 0;
441     /** the ratio of samples in : samples out - may be negative. This is NOT the same as the velocity as it incluides a resampling factor */
442     float shrink_factor = 1.f;
443     int swap_sign;
444     int qnt = 1;
445 
446     if (IS_VALID_CLIP(pulsed->playing_file)) qnt = afile->achans * (afile->asampsize >> 3);
447 
448 #ifdef DEBUG_PULSE
449     lives_printerr("playing... pulseFramesAvailable = %ld\n", pulseFramesAvailable);
450 #endif
451 
452     pulsed->num_calls++;
453 
454     /// not in use, just send silence
455     if (!pulsed->in_use || (pulsed->read_abuf > -1 && !LIVES_IS_PLAYING)
456         || ((((pulsed->fd < 0 || pulsed->seek_pos < 0 ||
457                (!mainw->multitrack && IS_VALID_CLIP(pulsed->playing_file) && pulsed->seek_pos > afile->afilesize))
458               && pulsed->read_abuf < 0) && ((mainw->agen_key == 0 && !mainw->agen_needs_reinit) || mainw->multitrack))
459             || pulsed->is_paused || (mainw->pulsed_read && mainw->pulsed_read->playing_file != -1))) {
460 
461       if (pulsed->seek_pos < 0 && IS_VALID_CLIP(pulsed->playing_file) && pulsed->in_arate > 0) {
462         pulsed->seek_pos += (double)(pulsed->in_arate / pulsed->out_arate) * nsamples * qnt;
463         pulsed->seek_pos = ALIGN_CEIL64(pulsed->seek_pos, qnt);
464         if (pulsed->seek_pos > 0) {
465           pad_bytes = -pulsed->real_seek_pos;
466           pulsed->real_seek_pos = pulsed->seek_pos = 0;
467         }
468       }
469 
470       if (IS_VALID_CLIP(pulsed->playing_file) && !mainw->multitrack
471           && pulsed->seek_pos > afile->afilesize && pulsed->in_arate < 0) {
472         pulsed->seek_pos += (pulsed->in_arate / pulsed->out_arate) * nsamples * pulsed->in_achans * pulsed->in_asamps / 8;
473         pulsed->seek_pos = ALIGN_CEIL64(pulsed->seek_pos - qnt, qnt);
474         if (pulsed->seek_pos < afile->afilesize) {
475           pad_bytes = (afile->afilesize - pulsed->real_seek_pos); // -ve val
476           pulsed->real_seek_pos = pulsed->seek_pos = afile->afilesize;
477         }
478       }
479 #ifdef DEBUG_PULSE
480       g_print("pt a3 %d\n", pulsed->in_use);
481 #endif
482 
483       if (!pad_bytes) {
484         sample_silence_pulse(pulsed, nsamples * pulsed->out_achans * pulsed->out_asamps >> 3, xbytes);
485         return;
486       }
487     }
488 
489     if (!mainw->audio_seek_ready && pulsed->playing_file != mainw->playing_file)
490       mainw->audio_seek_ready = TRUE;
491 
492     if (!mainw->audio_seek_ready) {
493       double dqnt;
494       size_t qnt;
495       int64_t rnd_samp;
496       frames_t rnd_frame;
497       if (!mainw->video_seek_ready) {
498         int64_t xusec = pulsed->extrausec;
499         sample_silence_pulse(pulsed, nsamples * pulsed->out_achans * pulsed->out_asamps >> 3, xbytes);
500         //pulsed->seek_pos += xbytes;
501         fwd_seek_pos = pulsed->real_seek_pos = pulsed->seek_pos;
502         pulsed->usec_start += (pulsed->extrausec - xusec);
503         pulsed->extrausec = xusec;
504         //mainw->startticks = mainw->currticks = lives_get_current_playback_ticks(mainw->origsecs, mainw->orignsecs, NULL);
505         return;
506         /// adjustment is .5 (rounding factor) + (if we switched clips) 1 frame (because video advances 1) + 1 (????)
507       }
508       dqnt = (double)afile->achans * afile->asampsize / 8.;
509       qnt = afile->achans * (afile->asampsize >> 3);
510       /* g_print("@ SYNCxx %d seek pos %ld = %f  ct %ld   st %ld\n", mainw->actual_frame, pulsed->seek_pos, */
511       /*         ((double)pulsed->seek_pos / (double)afile->arps / 4. * afile->fps + 1.), mainw->currticks, mainw->startticks); */
512       /* pulsed->seek_pos += afile->adirection * (double)(mainw->currticks - mainw->startticks) / TICKS_PER_SECOND_DBL */
513       /*                     * (double)(afile->arps  * qnt); */
514       rnd_frame = (frames_t)((double)pulsed->seek_pos / (double)afile->arate / dqnt * afile->fps
515                              + (afile->last_play_sequence != mainw->play_sequence ? .000001 : .5));
516       //g_print("RND frame is %d\n", rnd_frame + 1);
517       //g_print("VALXXX %d %d %d\n", mainw->play_sequence, afile->last_play_sequence, mainw->switch_during_pb);
518       rnd_frame += afile->adirection * (mainw->switch_during_pb && afile->last_play_sequence == mainw->play_sequence ? 1 : 0);
519       mainw->switch_during_pb = FALSE;
520       rnd_samp = (int64_t)((double)(rnd_frame + .00001) / afile->fps * (double)afile->arate + .5);
521       pulsed->seek_pos = (ssize_t)(rnd_samp * qnt);
522       //g_print("rndfr = %d rnt = %ld skpo = %ld\n", rnd_frame + 1, rnd_samp, pulsed->seek_pos);
523       pulsed->seek_pos = ALIGN_CEIL64(pulsed->seek_pos, qnt);
524       lives_lseek_buffered_rdonly_absolute(pulsed->fd, pulsed->seek_pos);
525       //g_print("seek to %ld %ld\n", pulsed->seek_pos, (int64_t)((double)pulsed->seek_pos / 48000. / 4. * afile->fps) + 1);
526       fwd_seek_pos = pulsed->real_seek_pos = pulsed->seek_pos;
527 
528       if (pulsed->playing_file == mainw->ascrap_file || afile->adirection == LIVES_DIRECTION_FORWARD) {
529         lives_buffered_rdonly_set_reversed(pulsed->fd, FALSE);
530       } else {
531         lives_buffered_rdonly_set_reversed(pulsed->fd, TRUE);
532       }
533 
534       shrink_factor = (float)pulsed->in_arate / (float)pulsed->out_arate / mainw->audio_stretch;
535       in_framesd = fabs((double)shrink_factor * (double)pulseFramesAvailable);
536 
537       // preload the buffer for first read
538       in_bytes = (size_t)(in_framesd * pulsed->in_achans * (pulsed->in_asamps >> 3));
539       lives_read_buffered(pulsed->fd, NULL, in_bytes * 8, TRUE);
540       lives_lseek_buffered_rdonly_absolute(pulsed->fd, pulsed->seek_pos);
541       //mainw->startticks = mainw->currticks = lives_get_current_playback_ticks(mainw->origsecs, mainw->orignsecs, NULL);
542 
543       /* g_print("@ SYNC %d seek pos %ld = %f  ct %ld   st %ld\n", mainw->actual_frame, pulsed->seek_pos, */
544       /*         ((double)pulsed->seek_pos / (double)afile->arps / 4. * afile->fps + 1.), mainw->currticks, mainw->startticks); */
545       sync_ready = TRUE;
546     }
547 
548     if (LIVES_LIKELY(pulseFramesAvailable > 0 && (pulsed->read_abuf > -1
549                      || (pulsed->aPlayPtr && pulsed->in_achans > 0) ||
550                      (((mainw->agen_key != 0 || mainw->agen_needs_reinit)
551                        && !mainw->preview) && !mainw->multitrack)))) {
552       if (LIVES_IS_PLAYING && pulsed->read_abuf > -1) {
553         // playing back from memory buffers instead of from file
554         // this is used in multitrack
555         from_memory = TRUE;
556         numFramesToWrite = pulseFramesAvailable;
557       } else {
558         // from file or audio generator
559         if (LIVES_LIKELY(pulsed->fd >= 0)) {
560           int playfile = mainw->playing_file;
561           pulsed->seek_end = 0;
562           if (mainw->agen_key == 0 && !mainw->agen_needs_reinit && IS_VALID_CLIP(pulsed->playing_file)) {
563             if (mainw->playing_sel) {
564               pulsed->seek_end = (int64_t)((double)(afile->end - 1.) / afile->fps * afile->arps) * afile->achans
565                                  * (afile->asampsize / 8);
566               if (pulsed->seek_end > afile->afilesize) pulsed->seek_end = afile->afilesize;
567             } else {
568               if (!mainw->loop_video) pulsed->seek_end = (int64_t)((double)(mainw->play_end - 1.) / afile->fps * afile->arps)
569                     * afile->achans * (afile->asampsize / 8);
570               else pulsed->seek_end = afile->afilesize;
571             }
572             if (pulsed->seek_end > afile->afilesize) pulsed->seek_end = afile->afilesize;
573           }
574           if (pulsed->seek_end == 0 || ((pulsed->playing_file == mainw->ascrap_file && !mainw->preview) && IS_VALID_CLIP(playfile)
575                                         && mainw->files[playfile]->achans > 0)) pulsed->seek_end = INT64_MAX;
576 
577           /// calculate how much to read
578           pulsed->aPlayPtr->size = 0;
579 
580           shrink_factor = (float)pulsed->in_arate / (float)pulsed->out_arate / mainw->audio_stretch;
581           in_framesd = fabs((double)shrink_factor * (double)pulseFramesAvailable);
582 
583           // add in a small random factor so on longer timescales we arent losing or gaining samples
584           in_bytes = (int)(in_framesd + ((double)fastrand() / (double)LIVES_MAXUINT64))
585                      * pulsed->in_achans * (pulsed->in_asamps >> 3);
586 
587 #ifdef DEBUG_PULSE
588           in_frames = in_bytes / pulsed->in_achans * (pulsed->in_asamps >> 3);
589           g_print("in bytes=%ld %d %d %lu %lu %lu\n", in_bytes, pulsed->in_arate, pulsed->out_arate, pulseFramesAvailable,
590                   pulsed->in_achans, pulsed->in_asamps);
591 #endif
592 
593           /// expand the buffer if necessary
594           if (LIVES_UNLIKELY((in_bytes > pulsed->aPlayPtr->max_size && !(*pulsed->cancelled) && fabsf(shrink_factor) <= 100.f))) {
595             boolean update_sbuffer = FALSE;
596             if (pulsed->sound_buffer == pulsed->aPlayPtr->data) update_sbuffer = TRUE;
597             if (pulsed->aPlayPtr->data) lives_free((void *)(pulsed->aPlayPtr->data));
598             pulsed->aPlayPtr->data = lives_calloc_safety(in_bytes >> 2, 4);
599             if (update_sbuffer) pulsed->sound_buffer = (void *)(pulsed->aPlayPtr->data);
600             if (pulsed->aPlayPtr->data) pulsed->aPlayPtr->max_size = in_bytes;
601             else pulsed->aPlayPtr->max_size = 0;
602           }
603 
604           // update looping mode
605           if (mainw->whentostop == NEVER_STOP || mainw->loop_cont) {
606             if (mainw->ping_pong && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS)
607                 && ((prefs->audio_opts & AUDIO_OPTS_FOLLOW_CLIPS) || mainw->current_file == pulsed->playing_file)
608                 && (!mainw->event_list || mainw->record || mainw->record_paused)
609                 && mainw->agen_key == 0 && !mainw->agen_needs_reinit)
610               pulsed->loop = AUDIO_LOOP_PINGPONG;
611             else pulsed->loop = AUDIO_LOOP_FORWARD;
612           } else {
613             pulsed->loop = AUDIO_LOOP_NONE;
614             //in_bytes = 0;
615           }
616 
617           pulsed->aPlayPtr->size = 0;
618 
619           if (shrink_factor  > 0.) {
620             // forward playback
621             if ((mainw->agen_key == 0 || mainw->multitrack || mainw->preview) && in_bytes > 0) {
622               lives_buffered_rdonly_set_reversed(pulsed->fd, FALSE);
623               if (pad_bytes < 0) pad_bytes = 0;
624               else {
625                 pad_bytes *= shrink_factor;
626                 pad_bytes = ALIGN_CEIL64(pad_bytes - qnt, qnt);
627               }
628               if (pad_bytes) lives_memset((void *)pulsed->aPlayPtr->data, 0, pad_bytes);
629               pulsed->aPlayPtr->size = lives_read_buffered(pulsed->fd, (void *)(pulsed->aPlayPtr->data + pad_bytes),
630                                        in_bytes - pad_bytes, TRUE) + pad_bytes;
631             } else pulsed->aPlayPtr->size = in_bytes;
632             pulsed->sound_buffer = (void *)(pulsed->aPlayPtr->data);
633             pulsed->seek_pos += in_bytes - pad_bytes;
634             if (pulsed->seek_pos >= pulsed->seek_end && !afile->opening) {
635               ssize_t rem = pulsed->seek_end - pulsed->real_seek_pos;
636               if (pulsed->aPlayPtr->size + rem > in_bytes) rem = in_bytes - pulsed->aPlayPtr->size;
637               if (rem > 0)
638                 pulsed->aPlayPtr->size += lives_read_buffered(pulsed->fd, (void *)(pulsed->aPlayPtr->data)
639                                           + pulsed->aPlayPtr->size,
640                                           pulsed->seek_end - pulsed->real_seek_pos, TRUE);
641 
642               if (pulsed->loop == AUDIO_LOOP_NONE) {
643                 if (*pulsed->whentostop == STOP_ON_AUD_END) *pulsed->cancelled = CANCEL_AUD_END;
644                 in_bytes = 0;
645                 pulsed->in_use = FALSE;
646               } else {
647                 if (pulsed->loop == AUDIO_LOOP_PINGPONG && (afile->pb_fps < 0. || clip_can_reverse(pulsed->playing_file))) {
648                   pulsed->in_arate = -pulsed->in_arate;
649                   afile->adirection = -afile->adirection;
650                   /// TODO - we should really read the first few bytes, however we dont yet support partial buffer reversals
651 
652                   pulsed->seek_pos = pulsed->seek_end;
653                   pulsed->seek_pos = ALIGN_CEIL64(pulsed->seek_pos - qnt, qnt);
654                   pulsed->real_seek_pos = pulsed->seek_pos;
655                 } else {
656                   do {
657                     if (mainw->playing_sel) {
658                       pulsed->seek_pos = (int64_t)((double)(afile->start - 1.) / afile->fps * afile->arps)
659                                          * afile->achans * (afile->asampsize / 8);
660                       pulsed->real_seek_pos = pulsed->seek_pos = ALIGN_CEIL64(pulsed->seek_pos, qnt);
661                     } else pulsed->seek_pos = 0;
662                     if (pulsed->seek_pos == pulsed->seek_end) break;
663                     lives_lseek_buffered_rdonly_absolute(pulsed->fd, pulsed->seek_pos);
664                     if (pulsed->aPlayPtr->size < in_bytes) {
665                       pulsed->aPlayPtr->size += lives_read_buffered(pulsed->fd, (void *)(pulsed->aPlayPtr->data)
666                                                 + pulsed->aPlayPtr->size, in_bytes - pulsed->aPlayPtr->size, TRUE);
667                       pulsed->real_seek_pos = pulsed->seek_pos = lives_buffered_offset(pulsed->fd);
668                     }
669                   } while (pulsed->aPlayPtr->size < in_bytes && !lives_read_buffered_eof(pulsed->fd));
670                   if (pulsed->aPlayPtr->size < in_bytes) {
671                     pad_bytes = in_bytes - pulsed->aPlayPtr->size;
672                     /// TODO: use pad_with_silence() for all padding
673                     lives_memset((void *)pulsed->aPlayPtr->data + in_bytes - pad_bytes, 0, pad_bytes);
674                     pulsed->aPlayPtr->size = in_bytes;
675                   }
676                 }
677               }
678               pulsed->seek_pos = ALIGN_CEIL64(pulsed->seek_pos - qnt, qnt);
679               fwd_seek_pos = pulsed->real_seek_pos = pulsed->seek_pos;
680               if (mainw->record && !mainw->record_paused) pulse_set_rec_avals(pulsed);
681             }
682           }
683 
684           else if (pulsed->playing_file != mainw->ascrap_file && shrink_factor  < 0.f) {
685             /// reversed playback
686             off_t seek_start = (mainw->playing_sel ?
687                                 (int64_t)((double)(afile->start - 1.) / afile->fps * afile->arps)
688                                 * afile->achans * (afile->asampsize / 8) : 0);
689             seek_start = ALIGN_CEIL64(seek_start - qnt, qnt);
690             if (pad_bytes > 0) pad_bytes = 0;
691             else {
692               if (pad_bytes < 0) {
693                 pad_bytes *= shrink_factor;
694                 pad_bytes = ALIGN_CEIL64(pad_bytes, qnt);
695                 /// pre-pad any silence (at end)
696                 lives_memset((void *)pulsed->aPlayPtr->data + in_bytes - pad_bytes, 0, pad_bytes);
697               }
698             }
699 
700             if ((pulsed->seek_pos -= (in_bytes - pad_bytes)) < seek_start) {
701               /// hit the (lower) bound
702               if (pulsed->loop == AUDIO_LOOP_NONE) {
703                 if (*pulsed->whentostop == STOP_ON_AUD_END) *pulsed->cancelled = CANCEL_AUD_END;
704                 in_bytes = 0;
705               } else {
706                 /// read remaining bytes
707                 lives_buffered_rdonly_set_reversed(pulsed->fd, TRUE);
708                 pulsed->seek_pos = ALIGN_CEIL64(seek_start, qnt);
709                 if (((mainw->agen_key == 0 && !mainw->agen_needs_reinit))) {
710                   lives_lseek_buffered_rdonly_absolute(pulsed->fd, pulsed->seek_pos);
711                   pulsed->aPlayPtr->size = lives_read_buffered(pulsed->fd,
712                                            (void *)(pulsed->aPlayPtr->data) + in_bytes - pad_bytes -
713                                            (pulsed->real_seek_pos - pulsed->seek_pos),
714                                            pulsed->real_seek_pos - pulsed->seek_pos, TRUE);
715                   if (pulsed->aPlayPtr->size < pulsed->real_seek_pos - seek_start) {
716                     /// short read, shift them up
717                     lives_memmove((void *)pulsed->aPlayPtr->data + in_bytes - pad_bytes - pulsed->aPlayPtr->size,
718                                   (void *)(pulsed->aPlayPtr->data) + in_bytes - pad_bytes -
719                                   (pulsed->real_seek_pos - seek_start), pulsed->aPlayPtr->size);
720                   }
721                 }
722 
723                 pulsed->aPlayPtr->size += pad_bytes;
724 
725                 /// bounce or loop round
726                 if (pulsed->loop == AUDIO_LOOP_PINGPONG) {
727                   /// TODO - we should really read the first few bytes, however we dont yet support partial buffer reversals
728                   pulsed->in_arate = -pulsed->in_arate;
729                   afile->adirection = -afile->adirection;
730                   pulsed->seek_pos = seek_start;
731                 } else {
732                   pulsed->seek_pos = pulsed->seek_end - pulsed->aPlayPtr->size;
733                 }
734               }
735               pulsed->seek_pos = ALIGN_CEIL64(pulsed->seek_pos - qnt, qnt);
736               fwd_seek_pos = pulsed->real_seek_pos = pulsed->seek_pos;
737               if (mainw->record && !mainw->record_paused) pulse_set_rec_avals(pulsed);
738             }
739 
740             if (((mainw->agen_key == 0 && !mainw->agen_needs_reinit)) && in_bytes - pulsed->aPlayPtr->size > 0) {
741               /// seek / read
742               pulsed->seek_pos = ALIGN_CEIL64(pulsed->seek_pos, qnt);
743               lives_lseek_buffered_rdonly_absolute(pulsed->fd, pulsed->seek_pos);
744               if (pulsed->playing_file == mainw->ascrap_file || pulsed->in_arate > 0) {
745                 lives_buffered_rdonly_set_reversed(pulsed->fd, FALSE);
746               } else {
747                 lives_buffered_rdonly_set_reversed(pulsed->fd, TRUE);
748                 if (pulsed->aPlayPtr->size < in_bytes) {
749                   pulsed->real_seek_pos = pulsed->seek_pos = ALIGN_CEIL64(pulsed->seek_pos, qnt);
750                   lives_lseek_buffered_rdonly_absolute(pulsed->fd, pulsed->seek_pos);
751                   pulsed->aPlayPtr->size
752                   += lives_read_buffered(pulsed->fd, (void *)(pulsed->aPlayPtr->data)
753                                          + pulsed->aPlayPtr->size,
754                                          in_bytes - pulsed->aPlayPtr->size, TRUE);
755 		  // *INDENT-OFF*
756 		}}}}
757 	  // *INDENT-ON*
758 
759           if (pulsed->aPlayPtr->size < in_bytes) {
760             /// if we are a few bytes short, pad with silence. If playing fwd we pad at the end, backwards we pad the beginning
761             /// (since the buffer will be reversed)
762             if (pulsed->in_arate > 0) {
763               pad_with_silence(-1, (void *)pulsed->aPlayPtr->data, pulsed->aPlayPtr->size, in_bytes,
764                                afile->asampsize >> 3, afile->signed_endian & AFORM_UNSIGNED,
765                                afile->signed_endian & AFORM_BIG_ENDIAN);
766             } else {
767               lives_memmove((void *)pulsed->aPlayPtr->data + (in_bytes - pulsed->aPlayPtr->size), (void *)pulsed->aPlayPtr->data,
768                             pulsed->aPlayPtr->size);
769               pad_with_silence(-1, (void *)pulsed->aPlayPtr->data, 0, in_bytes - pulsed->aPlayPtr->size,
770                                afile->asampsize >> 3, afile->signed_endian & AFORM_UNSIGNED,
771                                afile->signed_endian & AFORM_BIG_ENDIAN);
772             }
773           }
774         }
775 
776         /// put silence if anything changed
777         if (pulsed->mute || in_bytes == 0 || pulsed->aPlayPtr->size == 0 || !IS_VALID_CLIP(pulsed->playing_file)
778             || (!pulsed->aPlayPtr->data && ((mainw->agen_key == 0 && !mainw->agen_needs_reinit) ||
779                                             mainw->multitrack || mainw->preview))) {
780           sample_silence_pulse(pulsed, nsamples * pulsed->out_achans * (pulsed->out_asamps >> 3), xbytes);
781 #ifdef DEBUG_PULSE
782           g_print("pt a4\n");
783 #endif
784           return;
785         }
786 
787         if (mainw->agen_key != 0 && !mainw->multitrack && !mainw->preview) {
788           in_bytes = pulseFramesAvailable * pulsed->out_achans * 2;
789           if (xin_bytes == 0) xin_bytes = in_bytes;
790         }
791 
792         if ((mainw->agen_key == 0 && !mainw->agen_needs_reinit) || mainw->multitrack || (mainw->preview &&
793             !mainw->preview_rendering)) {
794           /// read from file
795           swap_sign = afile->signed_endian & AFORM_UNSIGNED;
796 
797           inputFramesAvailable = pulsed->aPlayPtr->size / (pulsed->in_achans * (pulsed->in_asamps >> 3));
798 #ifdef DEBUG_PULSE
799           lives_printerr("%ld inputFramesAvailable == %ld, %ld, %d %d,pulseFramesAvailable == %lu\n", pulsed->aPlayPtr->size,
800                          inputFramesAvailable,
801                          in_frames, pulsed->in_arate, pulsed->out_arate, pulseFramesAvailable);
802 #endif
803 
804           //// buffer is just a ref to pulsed->aPlayPtr->data
805           buffer = (uint8_t *)pulsed->aPlayPtr->data;
806           ////
807           numFramesToWrite = MIN(pulseFramesAvailable, (inputFramesAvailable / fabsf(shrink_factor) + .001)); // VALGRIND
808 
809 #ifdef DEBUG_PULSE
810           lives_printerr("inputFramesAvailable after conversion %ld\n", (uint64_t)((double)inputFramesAvailable
811                          / shrink_factor + .001));
812           lives_printerr("nsamples == %ld, pulseFramesAvailable == %ld,\n\tpulsed->num_input_channels == %ld, "
813                          "pulsed->out_achans == %ld\n",
814                          nsamples,
815                          pulseFramesAvailable, pulsed->in_achans, pulsed->out_achans);
816 #endif
817 
818           // pulsed->sound_buffer will either point to pulsed->aPlayPtr->data or will hold transformed audio
819           if (pulsed->in_asamps == pulsed->out_asamps && shrink_factor == 1. && pulsed->in_achans == pulsed->out_achans &&
820               !pulsed->reverse_endian && !swap_sign) {
821             // no transformation needed
822             pulsed->sound_buffer = buffer;
823           } else {
824             if (pulsed->sound_buffer != pulsed->aPlayPtr->data) lives_freep((void **)&pulsed->sound_buffer);
825 
826             pulsed->sound_buffer = (uint8_t *)lives_calloc_safety(pulsed->chunk_size >> 2, 4);
827 
828             if (!pulsed->sound_buffer) {
829               sample_silence_pulse(pulsed, nsamples * pulsed->out_achans * (pulsed->out_asamps >> 3), xbytes);
830 #ifdef DEBUG_PULSE
831               g_print("pt X2\n");
832 #endif
833               return;
834             }
835 
836             if (!from_memory) {
837               /// remove random factor if doing so gives a power of 2
838               if (in_bytes > in_framesd * pulsed->in_achans * (pulsed->in_asamps >> 3) && !((uint64_t)in_framesd & 1))
839                 in_bytes -= pulsed->in_achans * (pulsed->in_asamps >> 3);
840             }
841 
842             /// convert 8 bit to 16 if applicable, and resample to out rate
843             if (pulsed->in_asamps == 8) {
844               sample_move_d8_d16((short *)(pulsed->sound_buffer), (uint8_t *)buffer, nsamples, in_bytes,
845                                  shrink_factor, pulsed->out_achans, pulsed->in_achans, swap_sign ? SWAP_U_TO_S : 0);
846             } else {
847               sample_move_d16_d16((short *)pulsed->sound_buffer, (short *)buffer, nsamples, in_bytes, shrink_factor,
848                                   pulsed->out_achans, pulsed->in_achans, pulsed->reverse_endian ? SWAP_X_TO_L : 0,
849                                   swap_sign ? SWAP_U_TO_S : 0);
850             }
851           }
852 
853           if ((has_audio_filters(AF_TYPE_ANY) || mainw->ext_audio) && (pulsed->playing_file != mainw->ascrap_file)) {
854             boolean memok = TRUE;
855             float **fltbuf = (float **)lives_calloc(pulsed->out_achans, sizeof(float *));
856             register int i;
857             /// we have audio filters... convert to float, pass through any audio filters, then back to s16
858             for (i = 0; i < pulsed->out_achans; i++) {
859               // convert s16 to non-interleaved float
860               fltbuf[i] = (float *)lives_calloc_safety(nsamples, sizeof(float));
861               if (!fltbuf[i]) {
862                 memok = FALSE;
863                 for (--i; i >= 0; i--) {
864                   lives_freep((void **)&fltbuf[i]);
865                 }
866                 break;
867               }
868               /// convert to float, and take the opportunity to find the max volume
869               /// (currently this is used to trigger recording start optionally)
870               pulsed->abs_maxvol_heard = sample_move_d16_float(fltbuf[i], (short *)pulsed->sound_buffer + i,
871                                          nsamples, pulsed->out_achans, FALSE, FALSE, 1.0);
872             }
873 
874             if (memok) {
875               ticks_t tc = mainw->currticks;
876               // apply any audio effects with in_channels
877 
878               if (has_audio_filters(AF_TYPE_ANY)) {
879                 /** we create an Audio Layer and then call weed_apply_audio_effects_rt. The layer data is copied by ref
880                   to the in channel of the filter and then from the out channel back to the layer.
881                   IF the filter supports inplace then
882                   we get the same buffers back, otherwise we will get newly allocated ones, we copy by ref back to our audio buf
883                   and feed the result to the player as usual */
884                 weed_layer_t *layer = weed_layer_new(WEED_LAYER_TYPE_AUDIO);
885                 weed_layer_set_audio_data(layer, fltbuf, pulsed->out_arate, pulsed->out_achans, nsamples);
886                 weed_apply_audio_effects_rt(layer, tc, FALSE, TRUE);
887                 lives_free(fltbuf);
888                 fltbuf = weed_layer_get_audio_data(layer, NULL);
889                 weed_layer_set_audio_data(layer, NULL, 0, 0, 0);
890                 weed_layer_free(layer);
891               }
892 
893               pthread_mutex_lock(&mainw->vpp_stream_mutex);
894               if (mainw->ext_audio && mainw->vpp && mainw->vpp->render_audio_frame_float) {
895                 (*mainw->vpp->render_audio_frame_float)(fltbuf, numFramesToWrite);
896               }
897               pthread_mutex_unlock(&mainw->vpp_stream_mutex);
898 
899               // convert float audio back to s16 in pulsed->sound_buffer
900               sample_move_float_int(pulsed->sound_buffer, fltbuf, nsamples, 1.0, pulsed->out_achans, PA_SAMPSIZE, 0,
901                                     (capable->byte_order == LIVES_LITTLE_ENDIAN), FALSE, 1.0);
902 
903               for (i = 0; i < pulsed->out_achans; i++) {
904                 lives_free(fltbuf[i]);
905               }
906             }
907             lives_free(fltbuf);
908           }
909         } else {
910           // PULLING AUDIO FROM AN AUDIO GENERATOR
911           // get float audio from gen, convert it to S16
912           float **fltbuf = NULL;
913           boolean pl_error = FALSE;
914           xbytes = nbytes;
915           numFramesToWrite = pulseFramesAvailable;
916 
917           if (mainw->agen_needs_reinit) pl_error = TRUE;
918           else {
919             fltbuf = (float **)lives_malloc(pulsed->out_achans * sizeof(float *));
920             for (int i = 0; i < pulsed->out_achans; i++) fltbuf[i] =
921                 (float *)lives_calloc_safety(numFramesToWrite, sizeof(float));
922             if (!get_audio_from_plugin(fltbuf, pulsed->out_achans, pulsed->out_arate, numFramesToWrite, TRUE)) {
923               pl_error = TRUE;
924             }
925           }
926 
927           if (!pl_error) {
928             if (LIVES_UNLIKELY(nbytes > pulsed->aPlayPtr->max_size)) {
929               boolean update_sbuffer = FALSE;
930               if (pulsed->sound_buffer == pulsed->aPlayPtr->data) update_sbuffer = TRUE;
931               if (pulsed->aPlayPtr->data) lives_free((void *)(pulsed->aPlayPtr->data));
932               pulsed->aPlayPtr->data = lives_calloc_safety(nbytes / 4 + 1, 4);
933               //g_print("realloc 2\n");
934               if (update_sbuffer) pulsed->sound_buffer = (void *)(pulsed->aPlayPtr->data);
935               if (pulsed->aPlayPtr->data) {
936                 pulsed->aPlayPtr->max_size = nbytes;
937               } else {
938                 pulsed->aPlayPtr->size = pulsed->aPlayPtr->max_size = 0;
939                 pl_error = TRUE;
940               }
941             }
942             if (!pl_error) pulsed->aPlayPtr->size = nbytes;
943           }
944 
945           // get back non-interleaved float fbuffer; rate and channels should match
946           if (pl_error) nbytes = 0;
947           else {
948             boolean memok = FALSE;
949 
950             if (has_audio_filters(AF_TYPE_ANY) || mainw->ext_audio) {
951               memok = TRUE;
952               if (memok) {
953                 // apply any audio effects with in_channels
954                 ticks_t tc = mainw->currticks;
955                 if (has_audio_filters(AF_TYPE_ANY)) {
956                   weed_layer_t *layer = weed_layer_new(WEED_LAYER_TYPE_AUDIO);
957                   weed_layer_set_audio_data(layer, fltbuf, pulsed->out_arate, pulsed->out_achans, numFramesToWrite);
958                   weed_apply_audio_effects_rt(layer, tc, FALSE, TRUE);
959                   lives_free(fltbuf);
960                   fltbuf = weed_layer_get_audio_data(layer, NULL);
961                   weed_layer_set_audio_data(layer, NULL, 0, 0, 0);
962                   weed_layer_free(layer);
963                 }
964               }
965             }
966 
967             // streaming - we can push float audio to the playback plugin
968             pthread_mutex_lock(&mainw->vpp_stream_mutex);
969             if (mainw->ext_audio && mainw->vpp && mainw->vpp->render_audio_frame_float) {
970               (*mainw->vpp->render_audio_frame_float)(fltbuf, numFramesToWrite);
971             }
972             pthread_mutex_unlock(&mainw->vpp_stream_mutex);
973 
974             // copy effected audio back into pulsed->aPlayPtr->data
975             pulsed->sound_buffer = (uint8_t *)pulsed->aPlayPtr->data;
976 
977             sample_move_float_int(pulsed->sound_buffer, fltbuf, numFramesToWrite, 1.0,
978                                   pulsed->out_achans, PA_SAMPSIZE, 0, (capable->byte_order == LIVES_LITTLE_ENDIAN), FALSE, 1.0);
979 
980             if (fltbuf) {
981               for (register int i = 0; i < pulsed->out_achans; i++) lives_freep((void **)&fltbuf[i]);
982             }
983 
984             lives_free(fltbuf);
985             /// pl_error
986           }
987 
988           if (mainw->record && !mainw->record_paused && mainw->ascrap_file != -1 && mainw->playing_file > 0) {
989             /// if we are recording then write generated audio to ascrap_file
990             /// we may need to resample again to the file rate.
991             /// TODO: use markers to indicate when the rate changes, eliminating the necessity
992             size_t rbytes = numFramesToWrite * mainw->files[mainw->ascrap_file]->achans *
993                             mainw->files[mainw->ascrap_file]->asampsize >> 3;
994             pulse_flush_read_data(pulsed, mainw->ascrap_file,
995                                   nbytes, mainw->files[mainw->ascrap_file]->signed_endian & AFORM_BIG_ENDIAN,
996                                   pulsed->sound_buffer);
997             mainw->files[mainw->ascrap_file]->aseek_pos += rbytes;
998           }
999           /* // end from gen */
1000         }
1001 
1002         pulseFramesAvailable -= numFramesToWrite;
1003 
1004 #ifdef DEBUG_PULSE
1005         lives_printerr("pulseFramesAvailable == %ld\n", pulseFramesAvailable);
1006 #endif
1007 
1008         // playback from memory or file
1009         if (pulsed->playing_file > -1) clip_vol = lives_vol_from_linear(afile->vol);
1010         if (future_prefs->volume * clip_vol != pulsed->volume_linear) {
1011           // TODO: pa_threaded_mainloop_once_unlocked() (pa 13.0 +) ??
1012           pa_operation *paop;
1013           pavol = pa_sw_volume_from_linear(future_prefs->volume * clip_vol);
1014           pa_cvolume_set(&pulsed->volume, pulsed->out_achans, pavol);
1015           paop = pa_context_set_sink_input_volume(pulsed->con,
1016                                                   pa_stream_get_index(pulsed->pstream), &pulsed->volume, NULL, NULL);
1017           pa_operation_unref(paop);
1018           pulsed->volume_linear = future_prefs->volume * clip_vol;
1019         }
1020       }
1021     }
1022 
1023     // buffer is reused here, it's what we'll actually push to pulse
1024 
1025     if (sync_ready) sync_ready_ok(pulsed, nbytes);
1026 
1027     while (nbytes > 0) {
1028       if (nbytes < xbytes) xbytes = nbytes;
1029 
1030       if (!from_memory) {
1031 #if !HAVE_PA_STREAM_BEGIN_WRITE
1032         if (xbytes / pulsed->out_achans / (pulsed->out_asamps >> 3) <= numFramesToWrite && offs == 0) {
1033           buffer = pulsed->sound_buffer;
1034 #if 0
1035         }
1036       }
1037 #endif
1038 #else
1039         if (0) {
1040           // do nothing
1041         }
1042 #endif
1043       else {
1044         int ret = 0;
1045         if (pulsed->sound_buffer) {
1046 #if HAVE_PA_STREAM_BEGIN_WRITE
1047           xbytes = -1;
1048           // returns a buffer and a max size fo us to write to
1049           ret = pa_stream_begin_write(pulsed->pstream, (void **)&buffer, &xbytes);
1050           if (nbytes < xbytes) xbytes = nbytes;
1051 #else
1052           buffer = (uint8_t *)lives_calloc(nbytes, 1);
1053 #endif
1054         }
1055         if (!pulsed->sound_buffer || ret != 0 || !buffer) {
1056           sample_silence_pulse(pulsed, nsamples * pulsed->out_achans * (pulsed->out_asamps >> 3), nbytes);
1057 #ifdef DEBUG_PULSE
1058           g_print("pt X3\n");
1059 #endif
1060           return;
1061         }
1062         lives_memcpy(buffer, pulsed->sound_buffer + offs, xbytes);
1063         offs += xbytes;
1064         needs_free = TRUE;
1065       }
1066 
1067       /// we may also stream to a fifo, as well as possibly caching the audio for any video filters to utilize
1068       if (pulsed->astream_fd != -1) audio_stream(buffer, xbytes, pulsed->astream_fd);
1069       if (mainw->audio_frame_buffer && prefs->audio_src != AUDIO_SRC_EXT) {
1070         append_to_audio_buffer16(buffer, xbytes / 2, 0);
1071         mainw->audio_frame_buffer->samples_filled += xbytes / 2;
1072       }
1073 
1074       /// Finally... we actually write to pulse buffers
1075 #if !HAVE_PA_STREAM_BEGIN_WRITE
1076       pa_stream_write(pulsed->pstream, buffer, xbytes, buffer == pulsed->aPlayPtr->data ? NULL :
1077                       pulse_buff_free, 0, PA_SEEK_RELATIVE);
1078 #else
1079       pa_stream_write(pulsed->pstream, buffer, xbytes, NULL, 0, PA_SEEK_RELATIVE);
1080 #endif
1081       if (!sync_ready)
1082         pulsed->extrausec += ((double)xbytes / (double)(pulsed->out_arate) * 1000000.
1083                               / (double)(pulsed->out_achans * pulsed->out_asamps >> 3) + .5);
1084       pulsed->frames_written += xbytes / pulsed->out_achans / (pulsed->out_asamps >> 3);
1085     } else {
1086       // from memory (e,g multitrack)
1087       if (pulsed->read_abuf > -1 && !pulsed->mute) {
1088         int ret = 0;
1089 #if HAVE_PA_STREAM_BEGIN_WRITE
1090         xbytes = -1;
1091         ret = pa_stream_begin_write(pulsed->pstream, (void **)&shortbuffer, &xbytes);
1092 #endif
1093         if (nbytes < xbytes) xbytes = nbytes;
1094 #if !HAVE_PA_STREAM_BEGIN_WRITE
1095         shortbuffer = (short *)lives_calloc(xbytes);
1096 #endif
1097         if (!shortbuffer || ret != 0) {
1098           sample_silence_pulse(pulsed, nsamples * pulsed->out_achans * (pulsed->out_asamps >> 3), nbytes);
1099 #ifdef DEBUG_PULSE
1100           g_print("pt X4\n");
1101 #endif
1102           return;
1103         }
1104         sample_move_abuf_int16(shortbuffer, pulsed->out_achans, (xbytes >> 1) / pulsed->out_achans, pulsed->out_arate);
1105         if (pulsed->astream_fd != -1) audio_stream(shortbuffer, xbytes, pulsed->astream_fd);
1106 #if !HAVE_PA_STREAM_BEGIN_WRITE
1107         pa_stream_write(pulsed->pstream, shortbuffer, xbytes, pulse_buff_free, 0, PA_SEEK_RELATIVE);
1108 #else
1109         pa_stream_write(pulsed->pstream, shortbuffer, xbytes, NULL, 0, PA_SEEK_RELATIVE);
1110 #endif
1111         if (!sync_ready)
1112           pulsed->extrausec += ((double)xbytes / (double)(pulsed->out_arate) * 1000000.
1113                                 / (double)(pulsed->out_achans * pulsed->out_asamps >> 3) + .5);
1114         pulsed->frames_written += xbytes / pulsed->out_achans / (pulsed->out_asamps >> 3);
1115       } else {
1116         sample_silence_pulse(pulsed, xbytes, xbytes);
1117       }
1118     }
1119     nbytes -= xbytes;
1120   }
1121 
1122   if (needs_free && pulsed->sound_buffer != pulsed->aPlayPtr->data && pulsed->sound_buffer) {
1123     lives_freep((void **)&pulsed->sound_buffer);
1124   }
1125 
1126   fwd_seek_pos = pulsed->real_seek_pos = pulsed->seek_pos;
1127 
1128   if (pulseFramesAvailable) {
1129 #ifdef DEBUG_PULSE
1130     lives_printerr("buffer underrun of %ld frames\n", pulseFramesAvailable);
1131 #endif
1132     xbytes = pa_stream_writable_size(pstream);
1133     sample_silence_pulse(pulsed, pulseFramesAvailable * pulsed->out_achans * (pulsed->out_asamps >> 3), xbytes);
1134     if (!pulsed->is_paused) pulsed->frames_written += xbytes / pulsed->out_achans / (pulsed->out_asamps >> 3);
1135   }
1136 } else {
1137 #ifdef DEBUG_PULSE
1138   if (pulsed->state == PA_STREAM_UNCONNECTED || pulsed->state == PA_STREAM_CREATING)
1139     LIVES_INFO("pulseaudio stream UNCONNECTED or CREATING");
1140   else
1141     LIVES_WARN("pulseaudio stream FAILED or TERMINATED");
1142 #endif
1143 }
1144 #ifdef DEBUG_PULSE
1145 lives_printerr("done\n");
1146 #endif
1147 }
1148 
1149 
1150 size_t pulse_flush_read_data(pulse_driver_t *pulsed, int fileno, size_t rbytes, boolean rev_endian, void *data) {
1151   // prb is how many bytes to write, with rbytes as the latest addition
1152 
1153   short *gbuf;
1154   size_t bytes_out, frames_out, bytes = 0;
1155   void *holding_buff;
1156 
1157   float out_scale;
1158   int swap_sign;
1159 
1160   lives_clip_t *ofile;
1161 
1162   if (!data) data = prbuf;
1163 
1164   if (mainw->agen_key == 0 && !mainw->agen_needs_reinit) {
1165     if (prb == 0 || mainw->rec_samples == 0) return 0;
1166     if (prb <= PULSE_READ_BYTES * 2) {
1167       gbuf = (short *)data;
1168     } else {
1169       gbuf = (short *)lives_malloc(prb);
1170       if (!gbuf) return 0;
1171       if (prb > rbytes) lives_memcpy((void *)gbuf, prbuf, prb - rbytes);
1172       lives_memcpy((void *)gbuf + (prb - rbytes > 0 ? prb - rbytes : 0), data, rbytes);
1173     }
1174     ofile = afile;
1175   } else {
1176     if (rbytes == 0) return 0;
1177     if (fileno == -1) return 0;
1178     gbuf = (short *)data;
1179     prb = rbytes;
1180     ofile = mainw->files[fileno];
1181   }
1182 
1183   if (mainw->agen_key == 0 && !mainw->agen_needs_reinit) {
1184     out_scale = (float)pulsed->in_arate / (float)ofile->arate;
1185   } else out_scale = 1.;
1186 
1187   swap_sign = ofile->signed_endian & AFORM_UNSIGNED;
1188 
1189   frames_out = (size_t)((double)((prb / (ofile->asampsize >> 3) / ofile->achans)) / out_scale);
1190 
1191   if (mainw->agen_key == 0 && !mainw->agen_needs_reinit) {
1192     if (frames_out != pulsed->chunk_size) pulsed->chunk_size = frames_out;
1193   }
1194 
1195   bytes_out = frames_out * ofile->achans * (ofile->asampsize >> 3);
1196 
1197   holding_buff = lives_malloc(bytes_out);
1198 
1199   if (!holding_buff) {
1200     if (gbuf != (short *)data) lives_free(gbuf);
1201     prb = 0;
1202     return 0;
1203   }
1204 
1205   if (ofile->asampsize == 16) {
1206     sample_move_d16_d16((short *)holding_buff, gbuf, frames_out, prb, out_scale, ofile->achans, pulsed->in_achans,
1207                         pulsed->reverse_endian ? SWAP_L_TO_X : 0, swap_sign ? SWAP_S_TO_U : 0);
1208   } else {
1209     sample_move_d16_d8((uint8_t *)holding_buff, gbuf, frames_out, prb, out_scale, ofile->achans, pulsed->in_achans,
1210                        swap_sign ? SWAP_S_TO_U : 0);
1211   }
1212 
1213   if (gbuf != (short *)data) lives_free(gbuf);
1214 
1215   prb = 0;
1216 
1217   if (mainw->rec_samples > 0) {
1218     if (frames_out > mainw->rec_samples) frames_out = mainw->rec_samples;
1219     mainw->rec_samples -= frames_out;
1220   }
1221 
1222   if (!THREADVAR(bad_aud_file)) {
1223     size_t target = frames_out * (ofile->asampsize / 8) * ofile->achans, bytes;
1224     // use write not lives_write - because of potential threading issues
1225     bytes = write(mainw->aud_rec_fd, holding_buff, target);
1226     if (bytes > 0) {
1227       uint64_t chk = (mainw->aud_data_written & AUD_WRITE_CHECK);
1228       mainw->aud_data_written += bytes;
1229       if (IS_VALID_CLIP(mainw->ascrap_file) && mainw->aud_rec_fd == mainw->files[mainw->ascrap_file]->cb_src)
1230         add_to_ascrap_mb(bytes);
1231       check_for_disk_space((mainw->aud_data_written & AUD_WRITE_CHECK) != chk);
1232     }
1233     if (bytes < target) THREADVAR(bad_aud_file) = filename_from_fd(NULL, mainw->aud_rec_fd);
1234   }
1235 
1236   lives_free(holding_buff);
1237 
1238   return bytes;
1239 }
1240 
1241 
1242 static void pulse_audio_read_process(pa_stream * pstream, size_t nbytes, void *arg) {
1243   // read nsamples from pulse buffer, and then possibly write to mainw->aud_rec_fd
1244 
1245   // this is the callback from pulse when we are recording or playing external audio
1246 
1247   pulse_driver_t *pulsed = (pulse_driver_t *)arg;
1248   float out_scale;
1249   size_t frames_out, nsamples;
1250   void *data;
1251   size_t rbytes = nbytes, zbytes;
1252 
1253   pulsed->pstream = pstream;
1254 
1255   if (pulsed->is_corked) return;
1256 
1257   if (!pulsed->in_use || (mainw->playing_file < 0 && prefs->audio_src == AUDIO_SRC_EXT) || mainw->effects_paused) {
1258     pa_stream_peek(pulsed->pstream, (const void **)&data, &rbytes);
1259     if (rbytes > 0) {
1260       //g_print("PVAL %d\n", (*(uint8_t *)data & 0x80) >> 7);
1261       pa_stream_drop(pulsed->pstream);
1262     }
1263     prb = 0;
1264     if (pulsed->in_use)
1265       pulsed->extrausec += ((double)nbytes / (double)(pulsed->out_arate) * 1000000.
1266                             / (double)(pulsed->out_achans * pulsed->out_asamps >> 3) + .5);
1267     return;
1268   }
1269 
1270   zbytes = pa_stream_readable_size(pulsed->pstream);
1271 
1272   if (zbytes == 0) {
1273     //g_print("nothing to read from PA\n");
1274     return;
1275   }
1276 
1277   if (pa_stream_peek(pulsed->pstream, (const void **)&data, &rbytes)) {
1278     return;
1279   }
1280 
1281   if (!data) {
1282     if (rbytes > 0) {
1283       pa_stream_drop(pulsed->pstream);
1284     }
1285     return;
1286   }
1287 
1288   if (!mainw->fs && !mainw->faded && !mainw->multitrack && mainw->ext_audio_mon)
1289     lives_toggle_tool_button_set_active(LIVES_TOGGLE_TOOL_BUTTON(mainw->ext_audio_mon), (*(uint8_t *)data & 0x80) >> 7);
1290 
1291   // time interpolation
1292   pulsed->extrausec += ((double)rbytes / (double)(pulsed->out_arate) * 1000000.
1293                         / (double)(pulsed->out_achans * pulsed->out_asamps >> 3) + .5);
1294 
1295   pthread_mutex_lock(&mainw->audio_filewriteend_mutex);
1296 
1297   if (pulsed->playing_file == -1) {
1298     out_scale = 1.0; // just listening, no recording
1299   } else {
1300     out_scale = (float)afile->arate / (float)pulsed->in_arate; // recording to ascrap_file
1301   }
1302 
1303   if (mainw->record && mainw->record_paused && prb > 0) {
1304     // flush audio when recording is paused
1305     if (prb <= PULSE_READ_BYTES * 2) {
1306       lives_memcpy(&prbuf[prb - rbytes], data, rbytes);
1307       pulse_flush_read_data(pulsed, pulsed->playing_file, prb, pulsed->reverse_endian, prbuf);
1308     } else {
1309       pulse_flush_read_data(pulsed, pulsed->playing_file, rbytes, pulsed->reverse_endian, data);
1310     }
1311   }
1312 
1313   if (pulsed->playing_file == -1 || (mainw->record && mainw->record_paused)) prb = 0;
1314   else prb += rbytes;
1315 
1316   frames_out = (size_t)((double)((prb / (pulsed->in_asamps >> 3) / pulsed->in_achans)) / out_scale + .5);
1317 
1318   nsamples = (size_t)((double)((rbytes / (pulsed->in_asamps >> 3) / pulsed->in_achans)) / out_scale + .5);
1319 
1320   // should really be frames_read here
1321   if (!pulsed->is_paused) {
1322     pulsed->frames_written += nsamples;
1323   }
1324 
1325   if (prefs->audio_src == AUDIO_SRC_EXT && (pulsed->playing_file == -1 || pulsed->playing_file == mainw->ascrap_file)) {
1326     // - (do not call this when recording ext window or voiceover)
1327 
1328     // in this case we read external audio, but maybe not record it
1329     // we may wish to analyse the audio for example, or push it to a video generator
1330     // or stream it to the video playback plugin
1331 
1332     if ((!mainw->video_seek_ready && prefs->ahold_threshold > pulsed->abs_maxvol_heard)
1333         || has_audio_filters(AF_TYPE_A) || mainw->ext_audio) {
1334       // convert to float, apply any analysers
1335       boolean memok = TRUE;
1336       float **fltbuf = (float **)lives_malloc(pulsed->in_achans * sizeof(float *));
1337       register int i;
1338 
1339       size_t xnsamples = (size_t)(rbytes / (pulsed->in_asamps >> 3) / pulsed->in_achans);
1340 
1341       if (!fltbuf) {
1342         pthread_mutex_unlock(&mainw->audio_filewriteend_mutex);
1343         pa_stream_drop(pulsed->pstream);
1344         return;
1345       }
1346 
1347       for (i = 0; i < pulsed->in_achans; i++) {
1348         // convert s16 to non-interleaved float
1349         fltbuf[i] = (float *)lives_calloc(xnsamples, sizeof(float));
1350         if (!fltbuf[i]) {
1351           memok = FALSE;
1352           for (--i; i >= 0; i--) lives_free(fltbuf[i]);
1353           break;
1354         }
1355 
1356         pulsed->abs_maxvol_heard
1357           = sample_move_d16_float(fltbuf[i], (short *)(data) + i, xnsamples, pulsed->in_achans, FALSE, FALSE, 1.0);
1358 
1359         if (mainw->audio_frame_buffer && prefs->audio_src == AUDIO_SRC_EXT) {
1360           // if we have audio triggered gens., push audio to it
1361           append_to_audio_bufferf(fltbuf[i], xnsamples, i);
1362           if (i == pulsed->in_achans - 1) mainw->audio_frame_buffer->samples_filled += xnsamples;
1363         }
1364       }
1365 
1366       if (memok) {
1367         ticks_t tc = mainw->currticks;
1368         // apply any audio effects with in channels but no out channels (analysers)
1369 
1370         if (has_audio_filters(AF_TYPE_A)) {
1371           weed_layer_t *layer = weed_layer_new(WEED_LAYER_TYPE_AUDIO);
1372           weed_layer_set_audio_data(layer, fltbuf, pulsed->in_arate, pulsed->in_achans, xnsamples);
1373           weed_apply_audio_effects_rt(layer, tc, TRUE, TRUE);
1374           lives_free(fltbuf);
1375           fltbuf = weed_layer_get_audio_data(layer, NULL);
1376           weed_layer_free(layer);
1377         }
1378         // stream audio to video playback plugin if appropriate (probably needs retesting...)
1379         pthread_mutex_lock(&mainw->vpp_stream_mutex);
1380         if (mainw->ext_audio && mainw->vpp && mainw->vpp->render_audio_frame_float) {
1381           (*mainw->vpp->render_audio_frame_float)(fltbuf, xnsamples);
1382         }
1383         pthread_mutex_unlock(&mainw->vpp_stream_mutex);
1384         for (i = 0; i < pulsed->in_achans; i++) {
1385           lives_free(fltbuf[i]);
1386         }
1387       }
1388 
1389       lives_freep((void **)&fltbuf);
1390     }
1391   }
1392 
1393   if (pulsed->playing_file == -1 || (mainw->record && mainw->record_paused) || pulsed->is_paused) {
1394     pa_stream_drop(pulsed->pstream);
1395     if (pulsed->is_paused) {
1396       // This is NECESSARY to reduce / eliminate huge latencies.
1397 
1398       // TODO: pa_threaded_mainloop_once_unlocked() (pa 13.0 +)
1399       pa_operation *paop = pa_stream_flush(pulsed->pstream, NULL,
1400                                            NULL); // if not recording, flush the rest of audio (to reduce latency)
1401       pa_operation_unref(paop);
1402     }
1403     pthread_mutex_unlock(&mainw->audio_filewriteend_mutex);
1404     return;
1405   }
1406 
1407   if (mainw->playing_file != mainw->ascrap_file && IS_VALID_CLIP(mainw->playing_file))
1408     mainw->files[mainw->playing_file]->aseek_pos += rbytes;
1409   if (mainw->ascrap_file != -1 && !mainw->record_paused) mainw->files[mainw->ascrap_file]->aseek_pos += rbytes;
1410 
1411   pulsed->seek_pos += rbytes;
1412 
1413   if (prb < PULSE_READ_BYTES && (mainw->rec_samples == -1 || frames_out < mainw->rec_samples)) {
1414     // buffer until we have enough
1415     lives_memcpy(&prbuf[prb - rbytes], data, rbytes);
1416   } else {
1417     if (prb <= PULSE_READ_BYTES * 2) {
1418       lives_memcpy(&prbuf[prb - rbytes], data, rbytes);
1419       pulse_flush_read_data(pulsed, pulsed->playing_file, prb, pulsed->reverse_endian, prbuf);
1420     } else {
1421       pulse_flush_read_data(pulsed, pulsed->playing_file, rbytes, pulsed->reverse_endian, data);
1422     }
1423   }
1424 
1425   pa_stream_drop(pulsed->pstream);
1426   pthread_mutex_unlock(&mainw->audio_filewriteend_mutex);
1427 
1428   if (mainw->rec_samples == 0 && mainw->cancelled == CANCEL_NONE) {
1429     mainw->cancelled = CANCEL_KEEP; // we wrote the required #
1430   }
1431 }
1432 
1433 
1434 void pulse_shutdown(void) {
1435   //g_print("pa shutdown\n");
1436   if (pcon) {
1437     //g_print("pa shutdown2\n");
1438     pa_context_disconnect(pcon);
1439     pa_context_unref(pcon);
1440   }
1441   if (pa_mloop) {
1442     pa_threaded_mainloop_stop(pa_mloop);
1443     pa_threaded_mainloop_free(pa_mloop);
1444   }
1445   pcon = NULL;
1446   pa_mloop = NULL;
1447 }
1448 
1449 
1450 void pulse_close_client(pulse_driver_t *pdriver) {
1451   if (pdriver->pstream) {
1452     pa_mloop_lock();
1453     pa_stream_disconnect(pdriver->pstream);
1454     pa_stream_set_write_callback(pdriver->pstream, NULL, NULL);
1455     pa_stream_set_read_callback(pdriver->pstream, NULL, NULL);
1456     pa_stream_set_underflow_callback(pdriver->pstream, NULL, NULL);
1457     pa_stream_set_overflow_callback(pdriver->pstream, NULL, NULL);
1458     pa_stream_unref(pdriver->pstream);
1459     pa_mloop_unlock();
1460   }
1461   if (pdriver->pa_props) pa_proplist_free(pdriver->pa_props);
1462   pdriver->pa_props = NULL;
1463   pdriver->pstream = NULL;
1464 }
1465 
1466 
1467 int pulse_audio_init(void) {
1468   // initialise variables
1469   pulsed.in_use = FALSE;
1470   pulsed.mloop = pa_mloop;
1471   pulsed.con = pcon;
1472 
1473   //for (int j = 0; j < PULSE_MAX_OUTPUT_CHANS; j++) pulsed.volume.values[j] = pa_sw_volume_from_linear(future_prefs->volume);
1474   pulsed.volume_linear = future_prefs->volume;
1475   pulsed.state = (pa_stream_state_t)PA_STREAM_UNCONNECTED;
1476   pulsed.in_arate = 44100;
1477   pulsed.fd = -1;
1478   pulsed.seek_pos = pulsed.seek_end = pulsed.real_seek_pos = 0;
1479   pulsed.msgq = NULL;
1480   pulsed.num_calls = 0;
1481   pulsed.chunk_size = 0;
1482   pulsed.astream_fd = -1;
1483   pulsed.abs_maxvol_heard = 0.;
1484   pulsed.pulsed_died = FALSE;
1485   pulsed.aPlayPtr = (audio_buffer_t *)lives_malloc(sizeof(audio_buffer_t));
1486   pulsed.aPlayPtr->data = NULL;
1487   pulsed.aPlayPtr->size = 0;
1488   pulsed.aPlayPtr->max_size = 0;
1489   pulsed.in_achans = PA_ACHANS;
1490   pulsed.out_achans = PA_ACHANS;
1491   pulsed.out_asamps = PA_SAMPSIZE;
1492   pulsed.mute = FALSE;
1493   pulsed.out_chans_available = PULSE_MAX_OUTPUT_CHANS;
1494   pulsed.is_output = TRUE;
1495   pulsed.read_abuf = -1;
1496   pulsed.is_paused = FALSE;
1497   //pulsed.pstream = NULL;
1498   pulsed.pa_props = NULL;
1499   pulsed.playing_file = -1;
1500   pulsed.sound_buffer = NULL;
1501   pulsed.extrausec = 0;
1502   return 0;
1503 }
1504 
1505 
1506 int pulse_audio_read_init(void) {
1507   // initialise variables
1508 #if PA_SW_CONNECTION
1509   int j;
1510 #endif
1511 
1512   pulsed_reader.in_use = FALSE;
1513   pulsed_reader.mloop = pa_mloop;
1514   pulsed_reader.con = pcon;
1515 
1516   //for (j = 0; j < PULSE_MAX_OUTPUT_CHANS; j++) pulsed_reader.volume.values[j] = pa_sw_volume_from_linear(future_prefs->volume);
1517   pulsed_reader.state = (pa_stream_state_t)PA_STREAM_UNCONNECTED;
1518   pulsed_reader.fd = -1;
1519   pulsed_reader.seek_pos = pulsed_reader.seek_end = 0;
1520   pulsed_reader.msgq = NULL;
1521   pulsed_reader.num_calls = 0;
1522   pulsed_reader.chunk_size = 0;
1523   pulsed_reader.astream_fd = -1;
1524   pulsed_reader.abs_maxvol_heard = 0.;
1525   pulsed_reader.pulsed_died = FALSE;
1526   pulsed_reader.in_achans = PA_ACHANS;
1527   pulsed_reader.in_asamps = PA_SAMPSIZE;
1528   pulsed_reader.mute = FALSE;
1529   pulsed_reader.is_output = FALSE;
1530   pulsed_reader.is_paused = FALSE;
1531   pulsed_reader.pstream = NULL;
1532   pulsed_reader.pa_props = NULL;
1533   pulsed_reader.sound_buffer = NULL;
1534   pulsed_reader.extrausec = 0;
1535   return 0;
1536 }
1537 
1538 
1539 #if PA_SW_CONNECTION
1540 static void info_cb(pa_context * c, const pa_sink_input_info * i, int eol, void *userdata) {
1541   // would be great if this worked, but apparently it always returns NULL in i
1542   // for a hardware connection
1543 
1544   // TODO: get volume_writeable (pa 1.0+)
1545   pulse_driver_t *pdriver = (pulse_driver_t *)userdata;
1546   if (!i) return;
1547 
1548   pdrive->volume = i->volume;
1549   pdriver->volume_linear = pa_sw_volume_to_linear(i->volume.values[0]);
1550   pref_factory_float(PREF_MASTER_VOLUME, pdriver->volume_linear, TRUE);
1551   if (i->mute != mainw->mute) on_mute_activate(NULL, NULL);
1552 }
1553 #endif
1554 
1555 
1556 int pulse_driver_activate(pulse_driver_t *pdriver) {
1557   // create a new client and connect it to pulse server
1558   char *pa_clientname;
1559   char *mypid;
1560 
1561   pa_sample_spec pa_spec;
1562   pa_channel_map pa_map;
1563   pa_buffer_attr pa_battr;
1564 
1565   pa_operation *pa_op;
1566 
1567   if (pdriver->pstream) return 0;
1568 
1569   if (mainw->aplayer_broken) return 2;
1570 
1571   if (pdriver->is_output) {
1572     pa_clientname = "LiVES_audio_out";
1573   } else {
1574     pa_clientname = "LiVES_audio_in";
1575   }
1576 
1577   mypid = lives_strdup_printf("%d", capable->mainpid);
1578 
1579   pdriver->pa_props = pa_proplist_new();
1580 
1581   pa_proplist_sets(pdriver->pa_props, PA_PROP_APPLICATION_ICON_NAME, lives_get_application_name());
1582   pa_proplist_sets(pdriver->pa_props, PA_PROP_APPLICATION_ID, lives_get_application_name());
1583   pa_proplist_sets(pdriver->pa_props, PA_PROP_APPLICATION_NAME, lives_get_application_name());
1584 
1585   pa_proplist_sets(pdriver->pa_props, PA_PROP_APPLICATION_PROCESS_BINARY, capable->myname);
1586   pa_proplist_sets(pdriver->pa_props, PA_PROP_APPLICATION_PROCESS_ID, mypid);
1587   pa_proplist_sets(pdriver->pa_props, PA_PROP_APPLICATION_VERSION, LiVES_VERSION);
1588 
1589   lives_free(mypid);
1590 
1591 #ifdef GUI_GTK
1592   pa_proplist_sets(pdriver->pa_props, PA_PROP_APPLICATION_LANGUAGE, pango_language_to_string(gtk_get_default_language()));
1593 #endif
1594 
1595 #ifdef GUI_QT
1596   QLocale ql;
1597   pa_proplist_sets(pdriver->pa_props, PA_PROP_APPLICATION_LANGUAGE,
1598                    (QLocale::languageToString(ql.language())).toLocal8Bit().constData());
1599 #endif
1600 
1601   pa_channel_map_init_stereo(&pa_map);
1602 
1603   pa_spec.format = PA_SAMPLE_S16NE;
1604 
1605   pa_spec.channels = pdriver->out_achans = pdriver->in_achans;
1606 
1607   pdriver->in_asamps = pdriver->out_asamps = PA_SAMPSIZE;
1608   pdriver->out_signed = AFORM_SIGNED;
1609 
1610   if (capable->byte_order == LIVES_BIG_ENDIAN) {
1611     pdriver->out_endian = AFORM_BIG_ENDIAN;
1612     pa_spec.format = PA_SAMPLE_S16BE;
1613   } else {
1614     pdriver->out_endian = AFORM_LITTLE_ENDIAN;
1615     pa_spec.format = PA_SAMPLE_S16LE;
1616   }
1617 
1618   if (pdriver->is_output) {
1619     pa_battr.maxlength = LIVES_PA_BUFF_MAXLEN;
1620     pa_battr.tlength = LIVES_PA_BUFF_TARGET;
1621     pa_battr.minreq = LIVES_PA_BUFF_MINREQ * 2;
1622 
1623     /// TODO: kick off a thread to call the audio loop peridically (to receive command messages), on audio_seek == FALSE,
1624     // seek and fill the prefbuffer, then kill the thread loop and let pa take over. Must do the same on underflow though
1625     pa_battr.prebuf = 0;  /// must set this to zero else we hang, since pa is waiting for the buffer to be filled first
1626   } else {
1627     pa_battr.maxlength = LIVES_PA_BUFF_MAXLEN * 2;
1628     pa_battr.fragsize = LIVES_PA_BUFF_FRAGSIZE * 4;
1629     pa_battr.minreq = (uint32_t) - 1;
1630     pa_battr.prebuf = -1;
1631   }
1632 
1633   pa_mloop_lock();
1634   if (pulse_server_rate == 0) {
1635     pa_op = pa_context_get_server_info(pdriver->con, pulse_server_cb, pa_mloop);
1636     while (pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING) {
1637       pa_threaded_mainloop_wait(pa_mloop);
1638     }
1639     pa_operation_unref(pa_op);
1640   }
1641 
1642   if (pulse_server_rate == 0) {
1643     pa_mloop_unlock();
1644     LIVES_WARN("Problem getting pulseaudio rate...expect more problems ahead.");
1645     return 1;
1646   }
1647 
1648   pa_spec.rate = pdriver->out_arate = pdriver->in_arate = pulse_server_rate;
1649 
1650   pdriver->pstream = pa_stream_new_with_proplist(pdriver->con, pa_clientname, &pa_spec, &pa_map, pdriver->pa_props);
1651 
1652   /// TODO: try to set volume and mute state from sever reather then the other way round
1653 
1654   if (pdriver->is_output) {
1655     pa_volume_t pavol;
1656     pdriver->is_corked = TRUE;
1657 
1658     // set write callback
1659     pa_stream_set_write_callback(pdriver->pstream, pulse_audio_write_process, pdriver);
1660     pa_stream_set_underflow_callback(pdriver->pstream, stream_underflow_callback, pdriver);
1661     pa_stream_set_overflow_callback(pdriver->pstream, stream_overflow_callback, pdriver);
1662     pa_stream_set_moved_callback(pdriver->pstream, stream_moved_callback, pdriver);
1663     pa_stream_set_buffer_attr_callback(pdriver->pstream, stream_buffer_attr_callback, pdriver);
1664 
1665 #if PA_SW_CONNECTION
1666     pa_stream_connect_playback(pdriver->pstream, NULL, &pa_battr, (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY |
1667                                PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_START_CORKED |
1668                                PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL);
1669 #else
1670     pdriver->volume_linear = future_prefs->volume;
1671     pavol = pa_sw_volume_from_linear(pdriver->volume_linear);
1672     pa_cvolume_set(&pdriver->volume, pdriver->out_achans, pavol);
1673 
1674     // calling this may cause other streams to be interrupted temporarily
1675     // it seems impossible to avoid this
1676     pa_stream_connect_playback(pdriver->pstream, NULL, &pa_battr, (pa_stream_flags_t)(0
1677                                | PA_STREAM_RELATIVE_VOLUME
1678                                | PA_STREAM_INTERPOLATE_TIMING
1679                                | PA_STREAM_START_CORKED
1680                                | PA_STREAM_START_UNMUTED
1681                                | PA_STREAM_NOT_MONOTONIC
1682                                | PA_STREAM_AUTO_TIMING_UPDATE),
1683                                &pdriver->volume, NULL);
1684 #endif
1685     pa_mloop_unlock();
1686 
1687     while (pa_stream_get_state(pdriver->pstream) != PA_STREAM_READY) {
1688       sched_yield();
1689       lives_usleep(prefs->sleep_time);
1690     }
1691 
1692     pdriver->volume_linear = -1;
1693 
1694 #if PA_SW_CONNECTION
1695     // get the volume from the server
1696     pa_op = pa_context_get_sink_info(pdriver->con, info_cb, &pdriver);
1697 
1698     while (pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING) {
1699       sched_yield();
1700       lives_usleep(prefs->sleep_time);
1701     }
1702     pa_operation_unref(pa_op);
1703 #endif
1704   } else {
1705     // set read callback
1706     pdriver->frames_written = 0;
1707     pdriver->usec_start = 0;
1708     pdriver->in_use = FALSE;
1709     pdriver->abs_maxvol_heard = 0.;
1710     pdriver->is_corked = TRUE;
1711     prb = 0;
1712 
1713     pa_stream_set_underflow_callback(pdriver->pstream, stream_underflow_callback, pdriver);
1714     pa_stream_set_overflow_callback(pdriver->pstream, stream_overflow_callback, pdriver);
1715 
1716     pa_stream_set_moved_callback(pdriver->pstream, stream_moved_callback, pdriver);
1717     pa_stream_set_buffer_attr_callback(pdriver->pstream, stream_buffer_attr_callback, pdriver);
1718     pa_stream_set_read_callback(pdriver->pstream, pulse_audio_read_process, pdriver);
1719 
1720     pa_stream_connect_record(pdriver->pstream, NULL, &pa_battr,
1721                              (pa_stream_flags_t)(PA_STREAM_START_CORKED
1722                                  | PA_STREAM_ADJUST_LATENCY
1723                                  | PA_STREAM_INTERPOLATE_TIMING
1724                                  | PA_STREAM_AUTO_TIMING_UPDATE
1725                                  | PA_STREAM_NOT_MONOTONIC));
1726 
1727     pa_mloop_unlock();
1728     while (pa_stream_get_state(pdriver->pstream) != PA_STREAM_READY) {
1729       sched_yield();
1730       lives_usleep(prefs->sleep_time);
1731     }
1732   }
1733 
1734   return 0;
1735 }
1736 
1737 
1738 //#define DEBUG_PULSE_CORK
1739 static void uncorked_cb(pa_stream * s, int success, void *userdata) {
1740   pulse_driver_t *pdriver = (pulse_driver_t *)userdata;
1741 #ifdef DEBUG_PULSE_CORK
1742   g_print("uncorked %p\n", pdriver);
1743 #endif
1744   pdriver->is_corked = FALSE;
1745   prefs->force_system_clock = FALSE;
1746 }
1747 
1748 
1749 static void corked_cb(pa_stream * s, int success, void *userdata) {
1750   pulse_driver_t *pdriver = (pulse_driver_t *)userdata;
1751 #ifdef DEBUG_PULSE_CORK
1752   g_print("corked %p\n", pdriver);
1753 #endif
1754   pdriver->is_corked = TRUE;
1755   prefs->force_system_clock = TRUE;
1756   pa_threaded_mainloop_signal(pa_mloop, 0);
1757 }
1758 
1759 
1760 void pulse_driver_uncork(pulse_driver_t *pdriver) {
1761   pa_operation *paop;
1762   pdriver->abs_maxvol_heard = 0.;
1763   if (!pdriver->is_corked) return;
1764   pa_mloop_lock();
1765   paop = pa_stream_cork(pdriver->pstream, 0, uncorked_cb, pdriver);
1766   pa_mloop_unlock();
1767   if (pdriver->is_output) {
1768     pa_operation_unref(paop);
1769     return; // let it uncork in its own time...
1770   }
1771   pa_operation_unref(paop);
1772 }
1773 
1774 
1775 void pulse_driver_cork(pulse_driver_t *pdriver) {
1776   pa_operation *paop;
1777   ticks_t timeout;
1778   lives_alarm_t alarm_handle;
1779   if (pdriver->is_corked) {
1780     //g_print("IS CORKED\n");
1781     return;
1782   }
1783 
1784   do {
1785     alarm_handle = lives_alarm_set(LIVES_SHORTEST_TIMEOUT);
1786     pa_mloop_lock();
1787     paop = pa_stream_cork(pdriver->pstream, 1, corked_cb, pdriver);
1788     while (pa_operation_get_state(paop) == PA_OPERATION_RUNNING && (timeout = lives_alarm_check(alarm_handle)) > 0) {
1789       pa_threaded_mainloop_wait(pa_mloop);
1790     }
1791     pa_operation_unref(paop);
1792     pa_mloop_unlock();
1793     lives_alarm_clear(alarm_handle);
1794   } while (!timeout);
1795 
1796   pa_mloop_lock();
1797   paop = pa_stream_flush(pdriver->pstream, NULL, NULL);
1798   pa_operation_unref(paop);
1799   pa_mloop_unlock();
1800 }
1801 
1802 
1803 ///////////////////////////////////////////////////////////////
1804 
1805 LIVES_GLOBAL_INLINE pulse_driver_t *pulse_get_driver(boolean is_output) {
1806   if (is_output) return &pulsed;
1807   return &pulsed_reader;
1808 }
1809 
1810 
1811 LIVES_GLOBAL_INLINE volatile aserver_message_t *pulse_get_msgq(pulse_driver_t *pulsed) {
1812   if (pulsed->pulsed_died || mainw->aplayer_broken) return NULL;
1813   return pulsed->msgq;
1814 }
1815 
1816 
1817 boolean pa_time_reset(pulse_driver_t *pulsed, ticks_t offset) {
1818   int64_t usec;
1819   pa_operation *pa_op;
1820 
1821   if (!pulsed->pstream) return FALSE;
1822 
1823   pa_mloop_lock();
1824   pa_op = pa_stream_update_timing_info(pulsed->pstream, pulse_success_cb, pa_mloop);
1825 
1826   while (pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING) {
1827     pa_threaded_mainloop_wait(pa_mloop);
1828   }
1829   pa_operation_unref(pa_op);
1830   pa_mloop_unlock();
1831 
1832   while (pa_stream_get_time(pulsed->pstream, (pa_usec_t *)&usec) < 0) {
1833     lives_nanosleep(10000);
1834   }
1835   pulsed->usec_start = usec - offset  / USEC_TO_TICKS;
1836   pulsed->frames_written = 0;
1837   return TRUE;
1838 }
1839 
1840 
1841 /**
1842    @brief calculate the playback time based on samples sent to the soundcard
1843 */
1844 ticks_t lives_pulse_get_time(pulse_driver_t *pulsed) {
1845   // get the time in ticks since either playback started
1846   volatile aserver_message_t *msg;
1847   int64_t usec;
1848   ticks_t timeout, retval;
1849   lives_alarm_t alarm_handle;
1850 
1851   msg = pulsed->msgq;
1852   if (msg && (msg->command == ASERVER_CMD_FILE_SEEK || msg->command == ASERVER_CMD_FILE_OPEN)) {
1853     alarm_handle = lives_alarm_set(LIVES_SHORT_TIMEOUT);
1854     while ((timeout = lives_alarm_check(alarm_handle)) > 0 && pulse_get_msgq(pulsed)) {
1855       lives_nanosleep(1000);
1856     }
1857     lives_alarm_clear(alarm_handle);
1858     if (timeout == 0) return -1;
1859   }
1860   if (!CLIP_HAS_AUDIO(pulsed->playing_file) && !(LIVES_IS_PLAYING && pulsed->read_abuf > -1)) {
1861     return -1;
1862   }
1863   while (pa_stream_get_time(pulsed->pstream, (pa_usec_t *)&usec) < 0) {
1864     lives_nanosleep(10000);
1865   }
1866   retval = (ticks_t)((usec - pulsed->usec_start) * USEC_TO_TICKS);
1867   if (retval == -1) retval = 0;
1868   return retval;
1869 }
1870 
1871 
1872 double lives_pulse_get_pos(pulse_driver_t *pulsed) {
1873   // get current time position (seconds) in audio file
1874   //return (double)pulsed->real_seek_pos / (double)(afile->arps * afile->achans * afile->asampsize / 8);
1875   if (pulsed->playing_file > -1) {
1876     return (double)(fwd_seek_pos)
1877            / (double)(afile->arps * afile->achans * afile->asampsize / 8);
1878   }
1879   // from memory
1880   return (double)pulsed->frames_written / (double)pulsed->out_arate;
1881 }
1882 
1883 
1884 boolean pulse_audio_seek_frame(pulse_driver_t *pulsed, double frame) {
1885   // seek to frame "frame" in current audio file
1886   // position will be adjusted to (floor) nearest sample
1887   int64_t seekstart;
1888   double fps;
1889 
1890   if (frame > afile->frames && afile->frames > 0) frame = afile->frames;
1891   if (LIVES_IS_PLAYING) fps = fabs(afile->pb_fps);
1892   else fps = afile->fps;
1893 
1894   seekstart = (int64_t)(((frame - 1.) / fps
1895                          + (LIVES_IS_PLAYING ? (double)(mainw->currticks - mainw->startticks) / TICKS_PER_SECOND_DBL
1896                             * (pulsed->in_arate >= 0. ? 1.0 : -1.0) : 0.)) * (double)afile->arate)
1897               * afile->achans * afile->asampsize / 8;
1898 
1899   /* g_print("vals %ld and %ld %d\n", mainw->currticks, mainw->startticks, afile->arate); */
1900   /* g_print("bytes %f     %f       %d        %ld          %f\n", frame, afile->fps, LIVES_IS_PLAYING, seekstart, */
1901   /*         (double)seekstart / (double)afile->arate / 4.); */
1902   pulse_audio_seek_bytes(pulsed, seekstart, afile);
1903   return TRUE;
1904 }
1905 
1906 
1907 int64_t pulse_audio_seek_bytes(pulse_driver_t *pulsed, int64_t bytes, lives_clip_t *sfile) {
1908   // seek to position "bytes" in current audio file
1909   // position will be adjusted to (floor) nearest sample
1910 
1911   // if the position is > size of file, we will seek to the end of the file
1912   volatile aserver_message_t *pmsg;
1913   int qnt;
1914 
1915   // set this here so so that pulse_get_rev_avals returns the forward seek position
1916   fwd_seek_pos = bytes;
1917 
1918   if (!pulsed->is_corked) {
1919     ticks_t timeout;
1920     lives_alarm_t alarm_handle = lives_alarm_set(LIVES_SHORTEST_TIMEOUT);
1921     pmsg = pulse_get_msgq(pulsed);
1922     while (pmsg && pmsg->command != ASERVER_CMD_FILE_SEEK && (timeout = lives_alarm_check(alarm_handle)) > 0) {
1923       lives_nanosleep(1000);
1924       pmsg = pulse_get_msgq(pulsed);
1925     }
1926     lives_alarm_clear(alarm_handle);
1927 
1928     if (timeout == 0 || pulsed->playing_file == -1) {
1929       if (timeout == 0) LIVES_WARN("PA connect timed out");
1930       return 0;
1931     }
1932   }
1933 
1934   if (bytes < 0) bytes = 0;
1935   if (bytes > sfile->afilesize) bytes = sfile->afilesize;
1936 
1937   qnt = sfile->achans * (sfile->asampsize >> 3);
1938   bytes = ALIGN_CEIL64((int64_t)bytes, qnt);
1939 
1940   pulse_message2.command = ASERVER_CMD_FILE_SEEK;
1941   pulse_message2.next = NULL;
1942   pulse_message2.data = lives_strdup_printf("%"PRId64, bytes);
1943   pulse_message2.tc = 0;
1944   if (!pulsed->msgq) pulsed->msgq = &pulse_message2;
1945   else pulsed->msgq->next = &pulse_message2;
1946   return bytes;
1947 }
1948 
1949 
1950 boolean pulse_try_reconnect(void) {
1951   lives_alarm_t alarm_handle;
1952   do_threaded_dialog(_("Resetting pulseaudio connection..."), FALSE);
1953 
1954   pulse_shutdown();
1955   mainw->pulsed = NULL;
1956   if (prefs->pa_restart && !prefs->vj_mode) {
1957     char *com = lives_strdup_printf("%s %s", EXEC_PULSEAUDIO, prefs->pa_start_opts);
1958     lives_system(com, TRUE);
1959     lives_free(com);
1960   } else lives_system("pulseaudio -k", TRUE);
1961   alarm_handle = lives_alarm_set(LIVES_SHORT_TIMEOUT);
1962   while (lives_alarm_check(alarm_handle) > 0) {
1963     sched_yield();
1964     lives_usleep(prefs->sleep_time);
1965     threaded_dialog_spin(0.);
1966   }
1967   lives_alarm_clear(alarm_handle);
1968   if (!lives_pulse_init(9999)) {
1969     end_threaded_dialog();
1970     goto err123; // init server failed
1971   }
1972   pulse_audio_init(); // reset vars
1973   pulse_audio_read_init(); // reset vars
1974   mainw->pulsed = pulse_get_driver(TRUE);
1975   if (pulse_driver_activate(mainw->pulsed)) { // activate driver
1976     goto err123;
1977   }
1978   if (prefs->perm_audio_reader && prefs->audio_src == AUDIO_SRC_EXT) {
1979     // create reader connection now, if permanent
1980     pulse_rec_audio_to_clip(-1, -1, RECA_EXTERNAL);
1981   }
1982   end_threaded_dialog();
1983   d_print(_("\nConnection to pulseaudio was reset.\n"));
1984   return TRUE;
1985 
1986 err123:
1987   mainw->aplayer_broken = TRUE;
1988   mainw->pulsed = NULL;
1989   do_pulse_lost_conn_error();
1990   return FALSE;
1991 }
1992 
1993 
1994 /**
1995   @brief prepare to play file fileno
1996   - set loop mode
1997   - check if we need to reconnect
1998   - set vals
1999 */
2000 void pulse_aud_pb_ready(int fileno) {
2001   char *tmpfilename = NULL;
2002   lives_clip_t *sfile = mainw->files[fileno];
2003   int asigned = !(sfile->signed_endian & AFORM_UNSIGNED);
2004   int aendian = !(sfile->signed_endian & AFORM_BIG_ENDIAN);
2005 
2006   lives_freep((void **) & (mainw->pulsed->aPlayPtr->data));
2007   mainw->pulsed->aPlayPtr->size = mainw->pulsed->aPlayPtr->max_size = 0;
2008   if (mainw->pulsed) pulse_driver_uncork(mainw->pulsed);
2009 
2010   // called at pb start and rec stop (after rec_ext_audio)
2011   if (mainw->pulsed && mainw->aud_rec_fd == -1) {
2012     mainw->pulsed->is_paused = FALSE;
2013     mainw->pulsed->mute = mainw->mute;
2014     if ((mainw->loop_cont || mainw->whentostop != STOP_ON_AUD_END) && !mainw->preview) {
2015       if (mainw->ping_pong && prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS && !mainw->event_list)
2016         mainw->pulsed->loop = AUDIO_LOOP_PINGPONG;
2017       else mainw->pulsed->loop = AUDIO_LOOP_FORWARD;
2018     } else mainw->pulsed->loop = AUDIO_LOOP_NONE;
2019     if (sfile->achans > 0 && (!mainw->preview || (mainw->preview && mainw->is_processing)) &&
2020         (sfile->laudio_time > 0. || sfile->opening ||
2021          (mainw->multitrack && mainw->multitrack->is_rendering &&
2022           lives_file_test((tmpfilename = lives_get_audio_file_name(fileno)), LIVES_FILE_TEST_EXISTS)))) {
2023       ticks_t timeout;
2024       lives_alarm_t alarm_handle;
2025 
2026       lives_freep((void **)&tmpfilename);
2027       mainw->pulsed->in_achans = sfile->achans;
2028       mainw->pulsed->in_asamps = sfile->asampsize;
2029       mainw->pulsed->in_arate = sfile->arate;
2030       mainw->pulsed->usigned = !asigned;
2031       mainw->pulsed->seek_end = sfile->afilesize;
2032       mainw->pulsed->seek_pos = 0;
2033 
2034       if ((aendian && (capable->byte_order == LIVES_BIG_ENDIAN)) || (!aendian && (capable->byte_order == LIVES_LITTLE_ENDIAN)))
2035         mainw->pulsed->reverse_endian = TRUE;
2036       else mainw->pulsed->reverse_endian = FALSE;
2037 
2038       alarm_handle = lives_alarm_set(LIVES_SHORTEST_TIMEOUT);
2039       while ((timeout = lives_alarm_check(alarm_handle)) > 0 && pulse_get_msgq(mainw->pulsed)) {
2040         sched_yield(); // wait for seek
2041         lives_usleep(prefs->sleep_time);
2042       }
2043       lives_alarm_clear(alarm_handle);
2044 
2045       if (timeout == 0) pulse_try_reconnect();
2046 
2047       if ((!mainw->multitrack || mainw->multitrack->is_rendering ||
2048            sfile->opening) && (!mainw->event_list || mainw->record || (mainw->preview && mainw->is_processing))) {
2049         // tell pulse server to open audio file and start playing it
2050         pulse_message.command = ASERVER_CMD_FILE_OPEN;
2051         pulse_message.data = lives_strdup_printf("%d", fileno);
2052         pulse_message.next = NULL;
2053         mainw->pulsed->msgq = &pulse_message;
2054         pulse_audio_seek_bytes(mainw->pulsed, sfile->aseek_pos, sfile);
2055         if (seek_err) {
2056           if (pulse_try_reconnect()) pulse_audio_seek_bytes(mainw->pulsed, sfile->aseek_pos, sfile);
2057         }
2058         mainw->rec_aclip = fileno;
2059         mainw->rec_avel = sfile->pb_fps / sfile->fps;
2060         mainw->rec_aseek = (double)sfile->aseek_pos / (double)(sfile->arps * sfile->achans * (sfile->asampsize / 8));
2061       }
2062     }
2063     if (mainw->agen_key != 0 && !mainw->multitrack) mainw->pulsed->in_use = TRUE; // audio generator is active
2064   }
2065 }
2066 
2067 #undef afile
2068 
2069 #endif
2070 
2071