NOOP: remove line split for conditional
[ardour.git] / libs / ardour / butler.cc
1 /*
2     Copyright (C) 1999-2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23
24 #ifndef PLATFORM_WINDOWS
25 #include <poll.h>
26 #endif
27
28 #include "pbd/error.h"
29 #include "pbd/pthread_utils.h"
30
31 #include "ardour/butler.h"
32 #include "ardour/debug.h"
33 #include "ardour/disk_io.h"
34 #include "ardour/disk_reader.h"
35 #include "ardour/io.h"
36 #include "ardour/session.h"
37 #include "ardour/track.h"
38 #include "ardour/auditioner.h"
39
40 #include "pbd/i18n.h"
41
42 using namespace PBD;
43
44 namespace ARDOUR {
45
46 Butler::Butler(Session& s)
47         : SessionHandleRef (s)
48         , thread()
49         , have_thread (false)
50         , audio_dstream_capture_buffer_size(0)
51         , audio_dstream_playback_buffer_size(0)
52         , midi_dstream_buffer_size(0)
53         , pool_trash(16)
54         , _xthread (true)
55 {
56         g_atomic_int_set(&should_do_transport_work, 0);
57         SessionEvent::pool->set_trash (&pool_trash);
58
59         /* catch future changes to parameters */
60         Config->ParameterChanged.connect_same_thread (*this, boost::bind (&Butler::config_changed, this, _1));
61 }
62
63 Butler::~Butler()
64 {
65         terminate_thread ();
66 }
67
68 void
69 Butler::map_parameters ()
70 {
71         /* use any current ones that we care about */
72         boost::function<void (std::string)> ff (boost::bind (&Butler::config_changed, this, _1));
73         Config->map_parameters (ff);
74 }
75
76 void
77 Butler::config_changed (std::string p)
78 {
79         if (p == "playback-buffer-seconds") {
80                 _session.adjust_playback_buffering ();
81                 if (Config->get_buffering_preset() == Custom) {
82                         /* size is in Samples, not bytes */
83                         audio_dstream_playback_buffer_size = (uint32_t) floor (Config->get_audio_playback_buffer_seconds() * _session.frame_rate());
84                         _session.adjust_playback_buffering ();
85                 } else {
86 #ifndef NDEBUG
87                         std::cerr << "Skip explicit buffer seconds, preset in use\n";
88 #endif
89                 }
90         } else if (p == "capture-buffer-seconds") {
91                 if (Config->get_buffering_preset() == Custom) {
92                         audio_dstream_capture_buffer_size = (uint32_t) floor (Config->get_audio_capture_buffer_seconds() * _session.frame_rate());
93                         _session.adjust_capture_buffering ();
94                 } else {
95 #ifndef NDEBUG
96                         std::cerr << "Skip explicit buffer seconds, preset in use\n";
97 #endif
98                 }
99         } else if (p == "buffering-preset") {
100                 DiskIOProcessor::set_buffering_parameters (Config->get_buffering_preset());
101                 audio_dstream_capture_buffer_size = (uint32_t) floor (Config->get_audio_capture_buffer_seconds() * _session.frame_rate());
102                 audio_dstream_playback_buffer_size = (uint32_t) floor (Config->get_audio_playback_buffer_seconds() * _session.frame_rate());
103                 _session.adjust_capture_buffering ();
104                 _session.adjust_playback_buffering ();
105         } else if (p == "midi-readahead") {
106                 DiskReader::set_midi_readahead_frames ((framecnt_t) (Config->get_midi_readahead() * _session.frame_rate()));
107         }
108 }
109
110 int
111 Butler::start_thread()
112 {
113         // set up capture and playback buffering
114         DiskIOProcessor::set_buffering_parameters (Config->get_buffering_preset());
115
116         /* size is in Samples, not bytes */
117         const float rate = (float)_session.frame_rate();
118         audio_dstream_capture_buffer_size = (uint32_t) floor (Config->get_audio_capture_buffer_seconds() * rate);
119         audio_dstream_playback_buffer_size = (uint32_t) floor (Config->get_audio_playback_buffer_seconds() * rate);
120
121         /* size is in bytes
122          * XXX: AudioEngine needs to tell us the MIDI buffer size
123          * (i.e. how many MIDI bytes we might see in a cycle)
124          */
125         midi_dstream_buffer_size = (uint32_t) floor (Config->get_midi_track_buffer_seconds() * rate);
126
127         DiskReader::set_midi_readahead_frames ((framecnt_t) (Config->get_midi_readahead() * rate));
128
129         should_run = false;
130
131         if (pthread_create_and_store ("disk butler", &thread, _thread_work, this)) {
132                 error << _("Session: could not create butler thread") << endmsg;
133                 return -1;
134         }
135
136         //pthread_detach (thread);
137         have_thread = true;
138
139         // we are ready to request buffer adjustments
140         _session.adjust_capture_buffering ();
141         _session.adjust_playback_buffering ();
142
143         return 0;
144 }
145
146 void
147 Butler::terminate_thread ()
148 {
149         if (have_thread) {
150                 void* status;
151                 DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: ask butler to quit @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
152                 queue_request (Request::Quit);
153                 pthread_join (thread, &status);
154         }
155 }
156
157 void *
158 Butler::_thread_work (void* arg)
159 {
160         SessionEvent::create_per_thread_pool ("butler events", 4096);
161         pthread_set_name (X_("butler"));
162         return ((Butler *) arg)->thread_work ();
163 }
164
165 void *
166 Butler::thread_work ()
167 {
168         uint32_t err = 0;
169
170         bool disk_work_outstanding = false;
171         RouteList::iterator i;
172
173         while (true) {
174                 DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 butler main loop, disk work outstanding ? %2 @ %3\n", DEBUG_THREAD_SELF, disk_work_outstanding, g_get_monotonic_time()));
175
176                 if(!disk_work_outstanding) {
177                         DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 butler waits for requests @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
178
179                         char msg;
180                         /* empty the pipe of all current requests */
181                         if (_xthread.receive (msg, true) >= 0) {
182                                 Request::Type req = (Request::Type) msg;
183                                 switch (req) {
184
185                                         case Request::Run:
186                                                 DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: butler asked to run @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
187                                                 should_run = true;
188                                                 break;
189
190                                         case Request::Pause:
191                                                 DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: butler asked to pause @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
192                                                 should_run = false;
193                                                 break;
194
195                                         case Request::Quit:
196                                                 DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: butler asked to quit @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
197                                                 return 0;
198                                                 abort(); /*NOTREACHED*/
199                                                 break;
200
201                                         default:
202                                                 break;
203                                 }
204                         }
205                 }
206
207
208           restart:
209                 DEBUG_TRACE (DEBUG::Butler, "at restart for disk work\n");
210                 disk_work_outstanding = false;
211
212                 if (transport_work_requested()) {
213                         DEBUG_TRACE (DEBUG::Butler, string_compose ("do transport work @ %1\n", g_get_monotonic_time()));
214                         _session.butler_transport_work ();
215                         DEBUG_TRACE (DEBUG::Butler, string_compose ("\ttransport work complete @ %1, twr = %2\n", g_get_monotonic_time(), transport_work_requested()));
216                 }
217
218                 frameoffset_t audition_seek;
219                 if (should_run && _session.is_auditioning() && (audition_seek = _session.the_auditioner()->seek_frame()) >= 0) {
220                         boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (_session.the_auditioner());
221                         DEBUG_TRACE (DEBUG::Butler, "seek the auditioner\n");
222                         tr->seek(audition_seek);
223                         tr->do_refill ();
224                         _session.the_auditioner()->seek_response(audition_seek);
225                 }
226
227                 boost::shared_ptr<RouteList> rl = _session.get_routes();
228
229                 RouteList rl_with_auditioner = *rl;
230                 rl_with_auditioner.push_back (_session.the_auditioner());
231
232                 for (i = rl_with_auditioner.begin(); !transport_work_requested() && should_run && i != rl_with_auditioner.end(); ++i) {
233
234                         boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
235
236                         if (!tr) {
237                                 continue;
238                         }
239
240                         boost::shared_ptr<IO> io = tr->input ();
241
242                         if (io && !io->active()) {
243                                 /* don't read inactive tracks */
244                                 DEBUG_TRACE (DEBUG::Butler, string_compose ("butler skips inactive track %1\n", tr->name()));
245                                 continue;
246                         }
247                         DEBUG_TRACE (DEBUG::Butler, string_compose ("butler refills %1, playback load = %2\n", tr->name(), tr->playback_buffer_load()));
248                         switch (tr->do_refill ()) {
249                         case 0:
250                                 DEBUG_TRACE (DEBUG::Butler, string_compose ("\ttrack refill done %1\n", tr->name()));
251                                 break;
252
253                         case 1:
254                                 DEBUG_TRACE (DEBUG::Butler, string_compose ("\ttrack refill unfinished %1\n", tr->name()));
255                                 disk_work_outstanding = true;
256                                 break;
257
258                         default:
259                                 error << string_compose(_("Butler read ahead failure on dstream %1"), (*i)->name()) << endmsg;
260                                 std::cerr << string_compose(_("Butler read ahead failure on dstream %1"), (*i)->name()) << std::endl;
261                                 break;
262                         }
263
264                 }
265
266                 if (i != rl_with_auditioner.begin() && i != rl_with_auditioner.end()) {
267                         /* we didn't get to all the streams */
268                         disk_work_outstanding = true;
269                 }
270
271                 if (!err && transport_work_requested()) {
272                         DEBUG_TRACE (DEBUG::Butler, "transport work requested during refill, back to restart\n");
273                         goto restart;
274                 }
275
276                 disk_work_outstanding = flush_tracks_to_disk_normal (rl, err);
277
278                 if (err && _session.actively_recording()) {
279                         /* stop the transport and try to catch as much possible
280                            captured state as we can.
281                         */
282                         DEBUG_TRACE (DEBUG::Butler, "error occurred during recording - stop transport\n");
283                         _session.request_stop ();
284                 }
285
286                 if (!err && transport_work_requested()) {
287                         DEBUG_TRACE (DEBUG::Butler, "transport work requested during flush, back to restart\n");
288                         goto restart;
289                 }
290
291                 if (!disk_work_outstanding) {
292                         _session.refresh_disk_space ();
293                 }
294
295                 {
296                         Glib::Threads::Mutex::Lock lm (request_lock);
297
298                         if (should_run && (disk_work_outstanding || transport_work_requested())) {
299                                 DEBUG_TRACE (DEBUG::Butler, string_compose ("at end, should run %1 disk work %2 transport work %3 ... goto restart\n",
300                                                                             should_run, disk_work_outstanding, transport_work_requested()));
301                                 goto restart;
302                         }
303
304                         DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: butler signals pause @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
305                         paused.signal();
306                 }
307
308                 DEBUG_TRACE (DEBUG::Butler, "butler emptying pool trash\n");
309                 empty_pool_trash ();
310         }
311
312         return (0);
313 }
314
315 bool
316 Butler::flush_tracks_to_disk_normal (boost::shared_ptr<RouteList> rl, uint32_t& errors)
317 {
318         bool disk_work_outstanding = false;
319
320         for (RouteList::iterator i = rl->begin(); !transport_work_requested() && should_run && i != rl->end(); ++i) {
321
322                 // cerr << "write behind for " << (*i)->name () << endl;
323
324                 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
325
326                 if (!tr) {
327                         continue;
328                 }
329
330                 /* note that we still try to flush diskstreams attached to inactive routes
331                  */
332
333                 int ret;
334
335                 DEBUG_TRACE (DEBUG::Butler, string_compose ("butler flushes track %1 capture load %2\n", tr->name(), tr->capture_buffer_load()));
336                 ret = tr->do_flush (ButlerContext, false);
337                 switch (ret) {
338                 case 0:
339                         DEBUG_TRACE (DEBUG::Butler, string_compose ("\tflush complete for %1\n", tr->name()));
340                         break;
341
342                 case 1:
343                         DEBUG_TRACE (DEBUG::Butler, string_compose ("\tflush not finished for %1\n", tr->name()));
344                         disk_work_outstanding = true;
345                         break;
346
347                 default:
348                         errors++;
349                         error << string_compose(_("Butler write-behind failure on dstream %1"), (*i)->name()) << endmsg;
350                         std::cerr << string_compose(_("Butler write-behind failure on dstream %1"), (*i)->name()) << std::endl;
351                         /* don't break - try to flush all streams in case they
352                            are split across disks.
353                         */
354                 }
355         }
356
357         return disk_work_outstanding;
358 }
359
360 bool
361 Butler::flush_tracks_to_disk_after_locate (boost::shared_ptr<RouteList> rl, uint32_t& errors)
362 {
363         bool disk_work_outstanding = false;
364
365         /* almost the same as the "normal" version except that we do not test
366          * for transport_work_requested() and we force flushes.
367          */
368
369         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
370
371                 // cerr << "write behind for " << (*i)->name () << endl;
372
373                 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
374
375                 if (!tr) {
376                         continue;
377                 }
378
379                 /* note that we still try to flush diskstreams attached to inactive routes
380                  */
381
382                 int ret;
383
384                 DEBUG_TRACE (DEBUG::Butler, string_compose ("butler flushes track %1 capture load %2\n", tr->name(), tr->capture_buffer_load()));
385                 ret = tr->do_flush (ButlerContext, true);
386                 switch (ret) {
387                 case 0:
388                         DEBUG_TRACE (DEBUG::Butler, string_compose ("\tflush complete for %1\n", tr->name()));
389                         break;
390
391                 case 1:
392                         DEBUG_TRACE (DEBUG::Butler, string_compose ("\tflush not finished for %1\n", tr->name()));
393                         disk_work_outstanding = true;
394                         break;
395
396                 default:
397                         errors++;
398                         error << string_compose(_("Butler write-behind failure on dstream %1"), (*i)->name()) << endmsg;
399                         std::cerr << string_compose(_("Butler write-behind failure on dstream %1"), (*i)->name()) << std::endl;
400                         /* don't break - try to flush all streams in case they
401                            are split across disks.
402                         */
403                 }
404         }
405
406         return disk_work_outstanding;
407 }
408
409 void
410 Butler::schedule_transport_work ()
411 {
412         g_atomic_int_inc (&should_do_transport_work);
413         summon ();
414 }
415
416 void
417 Butler::queue_request (Request::Type r)
418 {
419         char c = r;
420         if (_xthread.deliver (c) != 1) {
421                 /* the x-thread channel is non-blocking
422                  * write may fail, but we really don't want to wait
423                  * under normal circumstances.
424                  *
425                  * a lost "run" requests under normal RT operation
426                  * is mostly harmless.
427                  *
428                  * TODO if ardour is freehweeling, wait & retry.
429                  * ditto for Request::Type Quit
430                  */
431                 assert(1); // we're screwd
432         }
433 }
434
435 void
436 Butler::summon ()
437 {
438         DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: summon butler to run @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
439         queue_request (Request::Run);
440 }
441
442 void
443 Butler::stop ()
444 {
445         Glib::Threads::Mutex::Lock lm (request_lock);
446         DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: asking butler to stop @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
447         queue_request (Request::Pause);
448         paused.wait(request_lock);
449 }
450
451 void
452 Butler::wait_until_finished ()
453 {
454         Glib::Threads::Mutex::Lock lm (request_lock);
455         DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: waiting for butler to finish @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
456         queue_request (Request::Pause);
457         paused.wait(request_lock);
458 }
459
460 bool
461 Butler::transport_work_requested () const
462 {
463         return g_atomic_int_get(&should_do_transport_work);
464 }
465
466 void
467 Butler::empty_pool_trash ()
468 {
469         /* look in the trash, deleting empty pools until we come to one that is not empty */
470
471         RingBuffer<CrossThreadPool*>::rw_vector vec;
472         pool_trash.get_read_vector (&vec);
473
474         guint deleted = 0;
475
476         for (int i = 0; i < 2; ++i) {
477                 for (guint j = 0; j < vec.len[i]; ++j) {
478                         if (vec.buf[i][j]->empty()) {
479                                 delete vec.buf[i][j];
480                                 ++deleted;
481                         } else {
482                                 /* found a non-empty pool, so stop deleting */
483                                 if (deleted) {
484                                         pool_trash.increment_read_idx (deleted);
485                                 }
486                                 return;
487                         }
488                 }
489         }
490
491         if (deleted) {
492                 pool_trash.increment_read_idx (deleted);
493         }
494 }
495
496 void
497 Butler::drop_references ()
498 {
499         std::cerr << "Butler drops pool trash\n";
500         SessionEvent::pool->set_trash (0);
501 }
502
503
504 } // namespace ARDOUR
505