I talked about Rotter in a previous post. This litte app connect to a Jack plug and record the audio to a file, in mp3, wav or other depending how you compiled it.
This app can also be told to spead files in a tree depending of the date, create a new file every X minutes and remove files older than X hours. Great.
But I had some crashed or unexpected exit. A friend of mine, already using it for a month or two said having no problem with it. But digging in the code let us find what the problem may be :

As we are recording in stereo, we are getting 2 ports from Jack. Then we create one stereo file (in wave).
The process is simple :
Inside a loop, check the jack ring-buffer to see if enough data is here. If yes, write a new chunk of sound. If not, wait for some time and check again.
I first found that the Jack ring-buffer check was made only on the first channel. As we are having 2 channels for stereo, what will happen if the first channel is filled up but not the second ?

Let me guess… a crash ?

NO :)
This little app is so well built that it will raise a fatal error and exit gracefuly.

So, what should I do ??
To be sure to have something recorded whatever happen I made 2 changes to the code (CC to the author) :
- check for both channels to be filled before writing sound
- only raise an error and not a fatal error, so « no sound » is recorded instead and the app continues to run.

Since then, no exit or crashed occured.

I had another problem. As my rotter is writing on a NFS mount, I also started a rotter to write on the local filesystem, just in case something goes wrong.
Then I started to see defunct processes like this :
goa 2059 20746 0 11:00 ? 00:00:00 [rotter]

The parent of the defuct process was the local rotter, which was still running fine and writing data.
Cutting the story short, I found it was the « deletion » of old files which was causing the problem. Reading through the code, the deletion process is a fork of the main program. But the main process never check for the child to return… so the child process is always hanging around (in a prent point of view).
Adding a quick « wait() » in the code partly solved the problem. I plane to change this to a « waitpid() » but I had to do this quick before going live.

I finaly changed the « wait » time of the loop. By default, rotter read the Jack ringbuffer once every Rotter-buffer-size/4. I changed it to Rotter-buffer-size/10 as my buffer was 40 seconds (so I check the buffer every 4 seconds… not too many).
In this cas, one can ask « why having a such big buffer if you read it less ? »
I don’t have the answer of this good question. Maybe the secret is to have a 8 seconds buffer and check Jack every 2 seconds ?

So there are the diffs to tweak the code :

diff -u rotter-0.5/src/sndfile.c rotter-0.5-new/src/sndfile.c
--- rotter-0.5/src/sndfile.c    2007-03-22 17:02:37.000000000 +0100
+++ rotter-0.5-new/src/sndfile.c        2007-09-06 00:26:35.000000000 +0200
@@ -70,9 +70,12 @@
        }

        // Is the enough in the ring buffer?
-       if (jack_ringbuffer_read_space( ringbuffer[0] ) < desired) {
+       for (c=0; c
+       {
+               if (jack_ringbuffer_read_space( ringbuffer[c] ) < desired) {
                // Try again later
                return 0;
+               }
        }

        // Get the audio out of the ring buffer
@@ -85,7 +88,7 @@
                // Copy frames from ring buffer to temporary buffer
         bytes_read = jack_ringbuffer_read( ringbuffer[c], (char*)tmp_buffer[c], desired);
                if (bytes_read != desired) {
-                       rotter_fatal( "Failed to read desired number of bytes from ringbuffer." );
+                       rotter_error( "Failed to read desired number of bytes %d from ringbuffer of %d on channel %d.", desired, bytes_read, c );
                }
     }
diff -ru rotter-0.5/src/rotter.c rotter-0.5-RTL/src/rotter.c
--- rotter-0.5/src/rotter.c     2007-06-01 03:57:38.000000000 +0200
+++ rotter-0.5-new/src/rotter.c 2008-03-06 12:06:46.000000000 +0100
@@ -200,7 +200,15 @@
                return 0;
        }

-       if (mkdir(dir, DEFAULT_DIR_MODE) < 0) {
+       // added by prune
+       // get the umask value (by stting it to 0) then set it back
+       mode_t mask = umask (0);
+        umask (mask);
+
+       // Compute the right mode
+       mode_t DIR_MODE = ((0777) ^ mask);
+
+       if (mkdir(dir, DIR_MODE) < 0) {
                if (errno == ENOENT) {
                        // ENOENT (a parent directory doesn't exist)
                        char* parent = strdup( dir );
@@ -219,7 +227,7 @@

                        // Try again to create the directory
                        if (result==0) {
-                               result = mkdir(dir, DEFAULT_DIR_MODE);
+                               result = mkdir(dir, DIR_MODE);
                        }

                } else {
@@ -382,9 +390,9 @@
                // Write some audio to disk
                int result = encoder->write();
                if (result == 0) {
-                       // Sleep for 1/4 of the ringbuffer duration
-                       rotter_debug("Failed to write some audio, sleeping for %f sec.", rb_duration/4);
-                       usleep( (rb_duration/4) * 1000000 );
+                       // Sleep for 1/10 of the ringbuffer duration
+                       rotter_debug("Failed to write some audio, sleeping for %f sec.", rb_duration/10);
+                       usleep( (rb_duration/10) * 1000000 );
                } else if (result < 0) {
                        rotter_fatal("Shutting down, due to encoding error.");
                        break;
diff -u rotter-0.5/src/deletefiles.c rotter-0.5-new/src/deletefiles.c
--- rotter-0.5/src/deletefiles.c        2007-03-22 17:02:37.000000000 +0100
+++ rotter-0.5-new/src/deletefiles.c    2007-09-06 01:29:11.000000000 +0200
@@ -30,6 +30,7 @@
 #include 

 #include 
+#include 
 #include 
 #include 

@@ -139,6 +140,9 @@
        rotter_info( "Deleting files older than %d hours in %s.", hours, dirpath );

+       int mychild;
+       wait(&mychild);
+
        // Fork a new process
        child_pid = fork();
        if (child_pid>0) {