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