nega0 / pianobarfly

pandora2[mp3|m4a]
https://github.com/nega0/pianobarfly
Other
62 stars 31 forks source link

Use temporary files to store audio stream (patch included) #65

Open fengshaun opened 8 years ago

fengshaun commented 8 years ago

Using a temporary file to keep the downloaded stream has the following advantages: 1- File is not saved to disk if it turns out it doesn't need to be saved (e.g. not rated) 2- If destination directory is a remote host (e.g. NFS share), then no unnecessary writes are made (i.e. if the file doesn't need to be saved).

things left to do:

diff --git a/src/fly.c b/src/fly.c
index ea93929..1fb6de3 100644
--- a/src/fly.c
+++ b/src/fly.c
@@ -1122,47 +1122,80 @@ void BarFlyFinalize(void)
    return;
 }

-int BarFlyClose(BarFly_t* fly, BarSettings_t const* settings)
+int BarFlyCopyCompleted(BarFly_t* fly, BarSettings_t const* settings)
 {
-   int exit_status = 0;
-   int status;
+   if (!fly) {
+       return 0;
+   }

-   assert(settings != NULL);
+   fly->status = COPYING;
+   fseek(fly->temp_file, 0, SEEK_SET);

-   if (fly != NULL) {
-       /*
-        * Close the file stream.
-        */
-       if (fly->audio_file != NULL) {
-           fclose(fly->audio_file);
-       }
+   /*
+    * Open a stream to the file.
+    */
+   int status = _BarFlyFileOpen(&fly->audio_file, fly->audio_file_path, settings);

-       /*
-        * Delete the file if it was not complete or not loved.
-        */
-       if (!fly->completed || (settings->downloadOnlyLoved && !fly->loved)) {
-           fly->status = DELETING;
-           status = _BarFlyFileDelete(fly, settings);
-           if (status != 0) {
-               exit_status = -1;
+   if (status == 0) {
+       char buf[BAR_FLY_COPY_BLOCK_SIZE];
+       memset(buf, 0, BAR_FLY_COPY_BLOCK_SIZE);
+       size_t s = 0, s2 = 0;
+
+       while (!feof(fly->temp_file)) {
+           s = fread(buf, 1, BAR_FLY_COPY_BLOCK_SIZE, fly->temp_file);
+
+           if (s != BAR_FLY_COPY_BLOCK_SIZE && !feof(fly->temp_file)) {
+               BarUiMsg(settings, MSG_INFO,
+                       "Could not read temporary file (%d): %s\n",
+                       errno,
+                       strerror(errno));
+               break;
            }
-       }

-       /*
-        * Free the audio file name.
-        */
-       if (fly->audio_file_path != NULL) {
-           free(fly->audio_file_path);
-       }
+           s2 = fwrite(buf, 1, s, fly->audio_file);

-       /*
-        * Free the cover art URL.
-        */
-       if (fly->cover_art_url != NULL) {
-           free(fly->cover_art_url);
+           if (s2 != s) {
+               BarUiMsg(settings, MSG_INFO,
+                       "Could not write audio to destination %s (%d): %s\n",
+                       fly->audio_file_path,
+                       errno,
+                       strerror(errno));
+               break;
+           }
        }
    }

+   fclose(fly->audio_file);
+}
+
+int BarFlyClose(BarFly_t* fly, BarSettings_t const* settings)
+{
+   if (!fly) {
+       return 0;
+   }
+
+   assert(settings != NULL);
+
+   int exit_status = 0;
+   int status;
+
+   /* closing the tmpfile() will delete it automatically */
+   fclose(fly->temp_file);
+
+   /*
+    * Free the audio file name.
+    */
+   if (fly->audio_file_path != NULL) {
+       free(fly->audio_file_path);
+   }
+
+   /*
+    * Free the cover art URL.
+    */
+   if (fly->cover_art_url != NULL) {
+       free(fly->cover_art_url);
+   }
+
    return exit_status;
 }

@@ -1347,22 +1380,17 @@ int BarFlyOpen(BarFly_t* fly, PianoSong_t const* song,
    if (output_fly.audio_file_path == NULL) {
        goto error;
    }
-   
+
    /*
-    * Open a stream to the file.
+    * Get a temporary file for download.
     */
-   status = _BarFlyFileOpen(&output_fly.audio_file,
-           output_fly.audio_file_path, settings);
-   if (status == 0) {
-       output_fly.status = RECORDING;
-   } else if (status == -2) {
-       output_fly.status = NOT_RECORDING_EXIST;
-       output_fly.completed = true;
-   } else {
-       output_fly.completed = true;
+   output_fly.temp_file = tmpfile();
+   if (output_fly.temp_file == NULL) {
        goto error;
    }

+   output_fly.status = RECORDING;
+
    /*
     * All members of the BarFly_t structure were created successfully.  Copy
     * them from the temporary structure to the one passed in.
@@ -1420,6 +1448,10 @@ char const* BarFlyStatusGet(BarFly_t* fly)
            string = "Deleting";
            break;

+       case (COPYING):
+           string = "Copying";
+           break;
+
        case (TAGGING):
            string = "Tagging";
            break;
@@ -1476,7 +1508,7 @@ int BarFlyWrite(BarFly_t* fly, void const* data, size_t data_size)
        }

        assert(fly->audio_file != NULL);
-       status = fwrite(data, data_size, 1, fly->audio_file);
+       status = fwrite(data, data_size, 1, fly->temp_file);
        if (status != 1) {
            goto error;
        }
diff --git a/src/fly.h b/src/fly.h
index e200512..e5551ac 100644
--- a/src/fly.h
+++ b/src/fly.h
@@ -52,6 +52,7 @@ typedef enum BarFlyStatus {
    NOT_RECORDING_EXIST,
    RECORDING,
    DELETING,
+   COPYING,
    TAGGING
 } BarFlyStatus_t;

@@ -63,11 +64,16 @@ typedef enum BarFlyStatus {
  */
 typedef struct BarFly {
    /**
-    * The stream to which the audio stream is written.
+    * The file to which the final audio stream is copied.
     */
    FILE* audio_file;

    /**
+    * The stream to which audio is written.
+    */
+   FILE* temp_file;
+
+   /**
     * The audio file path.
     */
    char* audio_file_path;
@@ -212,4 +218,13 @@ int BarFlyTag(BarFly_t* fly, BarSettings_t const* settings);
  */
 int BarFlyWrite(BarFly_t* fly, void const* data, size_t data_size);

+/**
+ * Copies the temporary audio file to final destination
+ *
+ * @param fly Pointer to a BarFly_t structure.
+ * @param settings Pointer to the application settings structure.
+ * @return Upon success 0 is returned otherwise -1 is returned.
+ */
+int BarFlyCopyCompleted(BarFly_t* fly, BarSettings_t const* settings);
+
 #endif /* _FLY_H */
diff --git a/src/player.c b/src/player.c
index 3c2cfdb..2ec35b1 100644
--- a/src/player.c
+++ b/src/player.c
@@ -518,8 +518,15 @@ void *BarPlayerThread (void *data) {
    } while (wRet == WAITRESS_RET_PARTIAL_FILE || wRet == WAITRESS_RET_TIMEOUT
            || wRet == WAITRESS_RET_READ_ERR);

-   /* If the song was played all the way through tag it. */
    if (wRet == WAITRESS_RET_OK) {
+       if (!player->settings->downloadOnlyLoved ||
+           (player->settings->downloadOnlyLoved && !player->fly.loved)) {
+           BarUiMsg(player->settings, MSG_INFO, "Saving loved song.\n",
+                   player->fly.audio_file_path);
+           BarFlyCopyCompleted(&player->fly, player->settings);
+       }
+
+       /* If the song was played all the way through tag it. */
        BarFlyTag(&player->fly, player->settings);
    }