示例#1
0
文件: scan.c 项目: EQ4/musicd
int scan_start()
{
  pthread_mutex_lock(&scan_mutex);
  if (thread_running) {
    /* Signal the scan thread to restart scanning */
    musicd_log(LOG_VERBOSE, "scan", "signaling to restart scan");
    restart = 1;
    interrupted = 1;
    pthread_mutex_unlock(&scan_mutex);
    return 0;
  }
  pthread_mutex_unlock(&scan_mutex);

  if (!config_get_value("music-directory")) {
    musicd_log(LOG_WARNING, "scan", "music-directory not set, no scanning");
    return 0;
  }

  thread_running = true;

  if (pthread_create(&scan_thread, NULL, scan_thread_func, NULL)) {
    musicd_perror(LOG_ERROR, "scan", "could not create thread");
    return -1;
  }
  pthread_detach(scan_thread);
  
  return 0;
}
示例#2
0
文件: session.c 项目: EQ4/musicd
static int purge_oldest_session()
{
  session_t *p, *oldest = NULL;
  for (p = sessions; p; p = p->next) {
    if (!oldest || (p->last_request < oldest->last_request && p->refs == 0)) {
      oldest = p;
    }
  }

  if (!oldest) {
    /* This block shouldn't execute without a bug related to dereferencing */
    musicd_log(LOG_WARNING, "session",
               "MAX_SESSIONS reached but all sessions in use");
    return -1;
  }

  musicd_log(LOG_DEBUG, "session", "MAX_SESSIONS reached, purging %s",
             oldest->id);

  if (oldest->prev) {
    oldest->prev->next = oldest->next;
  }
  if (oldest->next) {
    oldest->next->prev = oldest->prev;
  }
  if (sessions == oldest) {
    sessions = oldest->next;
  }

  free(oldest->id);
  free(oldest);

  --n_sessions;
  return 0;
}
示例#3
0
int64_t query_index(query_t *query, int64_t id)
{
  string_t *sql = string_new();
  char *where = build_filters(query);
  sqlite3_stmt *stmt;
  int64_t result;
  int64_t index = 1;

  string_append(sql, query->format->index);
  string_append(sql, query->format->from);
  string_append(sql, query->format->join);
  string_append(sql, where);
  free(where);

  if (string_size(query->order) > 0) {
    string_appendf(sql, " ORDER BY %s", string_string(query->order));
  }

  musicd_log(LOG_DEBUG, "query", "%s", string_string(sql));

  if (sqlite3_prepare_v2(db_handle(),
                         string_string(sql), -1,
                         &stmt, NULL) != SQLITE_OK) {
    musicd_log(LOG_ERROR, "query", "can't prepare '%s': %s",
               string_string(sql), db_error());
    string_free(sql);
    return -1;
  }
  string_free(sql);

  bind_filters(query, stmt);

  while (1) {
    result = sqlite3_step(stmt);
    if (result == SQLITE_DONE) {
      result = 0;
      goto finish;
    }
    if (result != SQLITE_ROW) {
      musicd_log(LOG_ERROR, "query", "query_count: sqlite3_step failed");
      result = -1;
      goto finish;
    }
    if (sqlite3_column_int64(stmt, 0) == id) {
      result = index;
      goto finish;
    }
    ++index;
  }

finish:
  sqlite3_finalize(stmt);
  return result;
}
示例#4
0
文件: library.c 项目: EQ4/musicd
/**
 * @todo FIXME More or less ugly value duplication.
 */
track_t *library_track_by_id(int64_t id)
{
  sqlite3_stmt *stmt;
  track_t *track;
  int result;

  static const char *sql =
    "SELECT rowid AS id, fileid, file, cuefileid, cuefile, track, title, artistid, artist, albumid, album, start, duration, trackindex FROM tracks WHERE rowid = ?";

  if (sqlite3_prepare_v2(db_handle(), sql, -1, &stmt, NULL) != SQLITE_OK) {
    musicd_log(LOG_ERROR, "library", "can't prepare '%s': %s", sql,
               db_error());
    return NULL;
  }

  sqlite3_bind_int(stmt, 1, id);

  result = sqlite3_step(stmt);
  if (result == SQLITE_DONE) {
    return NULL;
  } else if (result != SQLITE_ROW) {
    musicd_log(LOG_ERROR, "library", "library_track_by_id: sqlite3_step failed");
    return NULL;
  }

  track = track_new();
  track->id = sqlite3_column_int64(stmt, 0);
  track->fileid = sqlite3_column_int64(stmt, 1);
  track->file = strcopy((const char *)sqlite3_column_text(stmt, 2));
  track->cuefileid = sqlite3_column_int64(stmt, 3);
  track->cuefile = strcopy((const char *)sqlite3_column_text(stmt, 4));
  track->track = sqlite3_column_int(stmt, 5);
  track->title = strcopy((const char *)sqlite3_column_text(stmt, 6));
  track->artistid = sqlite3_column_int64(stmt, 7);
  track->artist = strcopy((const char *)sqlite3_column_text(stmt, 8));
  track->albumid = sqlite3_column_int64(stmt, 9);
  track->album = strcopy((const char *)sqlite3_column_text(stmt, 10));
  track->start = sqlite3_column_double(stmt, 11);
  track->duration = sqlite3_column_double(stmt, 12);
  track->trackindex = sqlite3_column_double(stmt, 13);

  /*musicd_log(LOG_DEBUG, "library", "%" PRId64 " %s %s %d %s %s %s %lf %lf",
             track->id, track->file, track->cuefile, track->track, track->title, track->artist,
             track->album, track->start, track->duration);*/

  sqlite3_finalize(stmt);

  return track;
}
示例#5
0
int query_tracks_next(query_t *query, track_t *track)
{
  int result;
  sqlite3_stmt *stmt;

  if (!query) {
    return -1;
  }

  stmt = query->stmt;

  result = sqlite3_step(stmt);
  if (result == SQLITE_DONE) {
    return 1;
  } else if (result != SQLITE_ROW) {
    musicd_log(LOG_ERROR, "query",
               "query_tracks_next: sqlite3_step failed");
    return -1;
  }

  track->id = sqlite3_column_int64(stmt, 0);
  track->file = (char *)sqlite3_column_text(stmt, 1);
  track->cuefile = (char *)sqlite3_column_text(stmt, 2);
  track->track = sqlite3_column_int(stmt, 3);
  track->title = (char *)sqlite3_column_text(stmt, 4);
  track->artistid = sqlite3_column_int64(stmt, 5);
  track->artist = (char *)sqlite3_column_text(stmt, 6);
  track->albumid = sqlite3_column_int64(stmt, 7);
  track->album = (char *)sqlite3_column_text(stmt, 8);
  track->start = sqlite3_column_int(stmt, 9);
  track->duration = sqlite3_column_int(stmt, 10);

  return 0;
}
示例#6
0
文件: lyrics.c 项目: EQ4/musicd
static lyrics_t *handle_lyrics_page(const char *page_name)
{
  char *url, *page, *lyrics;
  lyrics_t *result;

  url = url_escape_location("http://lyrics.wikia.com", page_name);
  page = url_fetch(url);
  if (!page) {
    musicd_log(LOG_ERROR, "lyrics", "can't fetch lyrics page");
    free(url);
    return NULL;
  }
  
  lyrics = parse_lyrics_page(page);
  free(page);

  if (!lyrics) {
    free(url);
    return NULL;
  }

  result = lyrics_new();
  result->lyrics = lyrics;
  result->provider = strcopy("LyricWiki");
  result->source = url;
  return result;
}
示例#7
0
文件: library.c 项目: EQ4/musicd
void library_iterate_images_by_album
  (int64_t album, bool (*callback)(library_image_t *file, void *opaque), void *opaque)
{
  static const char *sql =
    "SELECT images.rowid AS id, files.path AS path, files.directoryid AS directoryid FROM images JOIN files ON images.fileid = files.rowid WHERE images.albumid = ?;";
  sqlite3_stmt *query;
  int result;
  library_image_t image;
  bool cb_result = true;

  if (!prepare_query(sql, &query)) {
    return;
  }

  sqlite3_bind_int64(query, 1, album);

  image.album = album;

  while ((result = sqlite3_step(query)) == SQLITE_ROW) {
    image.id = sqlite3_column_int64(query, 0);
    image.path = (const char*)sqlite3_column_text(query, 1);
    image.directory = sqlite3_column_int64(query, 2);

    cb_result = callback(&image, opaque);
    if (cb_result == false) {
      break;
    }
  }
  if (result != SQLITE_DONE && result != SQLITE_ROW) {
    musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql);
  }

  sqlite3_finalize(query);
}
示例#8
0
文件: session.c 项目: EQ4/musicd
session_t *session_new()
{
  pthread_mutex_lock(&session_mutex);

  while (n_sessions >= MAX_SESSIONS && !purge_oldest_session()) { }

  session_t *session = malloc(sizeof(session_t));
  memset(session, 0, sizeof(session_t));

  session->id = generate_session_id();
  session->refs = 1;

  musicd_log(LOG_DEBUG, "session", "new session %s", session->id);

  if (sessions) {
    session->next = sessions;
    sessions->prev = session;
  }
  sessions = session;

  ++n_sessions;

  pthread_mutex_unlock(&session_mutex);
  return session;
}
示例#9
0
文件: library.c 项目: EQ4/musicd
char *library_image_path(int64_t image)
{
  static const char *sql =
    "SELECT files.path AS path FROM images JOIN files ON images.fileid = files.rowid WHERE images.rowid = ?";
  sqlite3_stmt *query;
  int result;
  char *path = NULL;;

  if (!prepare_query(sql, &query)) {
    return NULL;
  }

  sqlite3_bind_int64(query, 1, image);

  result = sqlite3_step(query);
  if (result != SQLITE_DONE && result != SQLITE_ROW) {
    musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql);
  }
  if (result == SQLITE_ROW) {
    path = strcopy((const char *)sqlite3_column_text(query, 0));
  }

  sqlite3_finalize(query);
  return path;
}
示例#10
0
文件: stream.c 项目: EQ4/musicd
static int mux_next(stream_t *stream)
{
  int result;
  AVPacket packet;

  do {
    result = get_next(stream);
    if (result <= 0) {
      return result;
    }
  } while (stream->dst_size == 0);

  av_init_packet(&packet);
  packet.data = stream->dst_data;
  packet.size = stream->dst_size;
  /*packet.pts = stream->pts;*/ /* FIXME: proper PTS/DTS handling */
  packet.stream_index = 0;

  result = av_interleaved_write_frame(stream->dst_ctx, &packet);
  if (result < 0) {
    musicd_log(LOG_ERROR, "stream",
               "av_interleaved_write_frame failed: %s",
               strerror(AVUNERROR(result)));
    return -1;
  }

  return 1;
}
示例#11
0
文件: library.c 项目: EQ4/musicd
void library_iterate_directories
  (int64_t parent,
   bool (*callback)(library_directory_t *directory, void *opaque),
   void *opaque)
{
  static const char *sql = "SELECT rowid, path, mtime, parentid FROM directories WHERE parentid = ?";
  sqlite3_stmt *query;
  int result;
  library_directory_t directory;
  bool cb_result;
  
  if (!prepare_query(sql, &query)) {
    return;
  }
  
  sqlite3_bind_int64(query, 1, parent);
  
  while ((result = sqlite3_step(query)) == SQLITE_ROW) {
    directory.id = sqlite3_column_int64(query, 0);
    directory.path = (const char*)sqlite3_column_text(query, 1);
    directory.mtime = sqlite3_column_int64(query, 2);
    directory.parent = sqlite3_column_int64(query, 3);
    
    cb_result = callback(&directory, opaque);
    if (cb_result == false) {
      break;
    }
  }
  if (result != SQLITE_DONE && result != SQLITE_ROW) {
    musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql);
  }
  
  sqlite3_finalize(query);
}
示例#12
0
文件: library.c 项目: EQ4/musicd
char *library_directory_path(int64_t directory)
{
  static const char *sql =
    "SELECT path FROM directories WHERE rowid = ?";
  sqlite3_stmt *query;
  int result;
  char *path = NULL;;

  if (!prepare_query(sql, &query)) {
    return NULL;
  }

  sqlite3_bind_int64(query, 1, directory);

  result = sqlite3_step(query);
  if (result != SQLITE_DONE && result != SQLITE_ROW) {
    musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql);
  }
  if (result == SQLITE_ROW) {
    path = strcopy((const char *)sqlite3_column_text(query, 0));
  }

  sqlite3_finalize(query);
  return path;
}
示例#13
0
文件: library.c 项目: EQ4/musicd
void library_iterate_files_by_directory
  (int64_t directory, bool (*callback)(library_file_t *file))
{
  static const char *sql = "SELECT rowid, path, mtime, directoryid FROM files WHERE directoryid = ?";
  sqlite3_stmt *query;
  int result;
  library_file_t file;
  bool cb_result = true;
  
  if (!prepare_query(sql, &query)) {
    return;
  }
  
  sqlite3_bind_int64(query, 1, directory);
  
  while ((result = sqlite3_step(query)) == SQLITE_ROW) {
    file.id = sqlite3_column_int64(query, 0);
    file.path = (const char*)sqlite3_column_text(query, 1);
    file.mtime = sqlite3_column_int64(query, 2);
    file.directory = sqlite3_column_int64(query, 3);
    
    cb_result = callback(&file);
    if (cb_result == false) {
      break;
    }
  }
  if (result != SQLITE_DONE && result != SQLITE_ROW) {
    musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql);
  }
  
  sqlite3_finalize(query);
}
示例#14
0
int query_albums_next(query_t *query, query_album_t *album)
{
  int result;
  sqlite3_stmt *stmt;

  if (!query) {
    return -1;
  }

  stmt = query->stmt;

  result = sqlite3_step(stmt);
  if (result == SQLITE_DONE) {
    return 1;
  } else if (result != SQLITE_ROW) {
    musicd_log(LOG_ERROR, "query",
               "query_albums_next: sqlite3_step failed");
    return -1;
  }

  album->albumid = sqlite3_column_int64(stmt, 0);
  album->album = (char *)sqlite3_column_text(stmt, 1);
  album->image = sqlite3_column_int64(stmt, 2);
  album->tracks = sqlite3_column_int64(stmt, 3);

  return 0;
}
示例#15
0
int query_artists_next(query_t *query, query_artist_t *artist)
{
  int result;
  sqlite3_stmt *stmt;

  if (!query) {
    return -1;
  }

  stmt = query->stmt;

  result = sqlite3_step(stmt);
  if (result == SQLITE_DONE) {
    return 1;
  } else if (result != SQLITE_ROW) {
    musicd_log(LOG_ERROR, "query",
               "query_artists_next: sqlite3_step failed");
    return -1;
  }

  artist->artistid = sqlite3_column_int64(stmt, 0);
  artist->artist = (char *)sqlite3_column_text(stmt, 1);

  return 0;
}
示例#16
0
文件: lyrics.c 项目: EQ4/musicd
/**
 * LyricsWiki fetching
 */
lyrics_t *lyrics_fetch(const track_t *track)
{
  char *url, *page, *page_name, *artist;
  char *p;
  lyrics_t *lyrics;

  /* Try the exact page */

  page_name = stringf("%s:%s", track->artist, track->title);
  lyrics = handle_lyrics_page(page_name);
  free(page_name);
  if (lyrics) {
    return lyrics;
  }


  /* Try finding the exact song from API search and try that exact page */

  artist = url_escape(track->artist);
  url = stringf(
    "http://lyrics.wikia.com/api.php?func=getArtist&artist=%s&fmt=text",
    artist);
  free(artist);
  page = url_fetch(url);
  free(url);
  if (!page) {
    musicd_log(LOG_ERROR, "lyrics", "can't fetch artist search");
    return NULL;
  }
  
  page_name = find_lyrics_page_name(page, track->title);
  if (page_name) {
    lyrics = handle_lyrics_page(page_name);
    free(page_name);
    if (lyrics) {
      goto finish;
    }
  }


  /* Try finding the exact artist name and use that like in the first step */

  p = strchr(page, ':');
  if (p) {
    *p = '\0';
    page_name = stringf("%s:%s", page, track->title);
    lyrics = handle_lyrics_page(page_name);
    free(page_name);
    if (lyrics) {
      goto finish;
    }
  }

finish:
  free(page);
  return lyrics;
}
示例#17
0
文件: library.c 项目: EQ4/musicd
static bool prepare_query(const char *sql, sqlite3_stmt **query)
{
  if (sqlite3_prepare_v2(db_handle(), sql, -1, query, NULL) != SQLITE_OK) {
    musicd_log(LOG_ERROR, "library", "can't prepare '%s': %s",
               sql, db_error());
    return false;
  }
  return true;
}
示例#18
0
文件: scan.c 项目: EQ4/musicd
static void scan()
{
  const char *raw_path = config_to_path("music-directory");
  char *path;
  time_t now;
  
  if (raw_path == NULL) {
    musicd_log(LOG_INFO, "scan", "music-directory not set, not scanning");
    return;
  }
  
  path = strcopy(raw_path);
  
  /* Strip possible trailing / */
  if (path[strlen(path) - 1] == '/') {
    path[strlen(path) - 1] = '\0';
  }
  
  
  last_scan = db_meta_get_int("last-scan");
  now = time(NULL);
  
  musicd_log(LOG_INFO, "scan", "starting");
  
  signal(SIGINT, scan_signal_handler);
  
  scan_directory(path, 0);
  
  free(path);
  
  signal(SIGINT, NULL);
  
  if (interrupted) {  
    musicd_log(LOG_INFO, "scan", "interrupted");
    return;
  }
  
  musicd_log(LOG_INFO, "scan", "finished");
  
  db_meta_set_int("last-scan", now);
}
示例#19
0
文件: library.c 项目: EQ4/musicd
static bool execute(sqlite3_stmt *query)
{
  int result = sqlite3_step(query);
  if (result == SQLITE_DONE || result == SQLITE_ROW) {
    result = true;
  } else {
    musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'",
               sqlite3_sql(query));
    result = false;
  }
  sqlite3_finalize(query);
  return result;
}
示例#20
0
int64_t query_count(query_t *query)
{
  string_t *sql = string_new();
  char *where = build_filters(query);
  sqlite3_stmt *stmt;
  int64_t result;
  
  string_append(sql, query->format->count);
  string_append(sql, query->format->from);
  string_append(sql, query->format->join);
  string_append(sql, where);
  free(where);

  musicd_log(LOG_DEBUG, "query", "%s", string_string(sql));

  if (sqlite3_prepare_v2(db_handle(),
                         string_string(sql), -1,
                         &stmt, NULL) != SQLITE_OK) {
    musicd_log(LOG_ERROR, "query", "can't prepare '%s': %s",
               string_string(sql), db_error());
    string_free(sql);
    return -1;
  }
  string_free(sql);

  bind_filters(query, stmt);

  result = sqlite3_step(stmt);
  if (result != SQLITE_ROW) {
    musicd_log(LOG_ERROR, "query", "query_count: sqlite3_step failed");
    result = -1;
    goto finish;
  }
  result = sqlite3_column_int64(stmt, 0);

finish:
  sqlite3_finalize(stmt);
  return result;
}
示例#21
0
文件: scan.c 项目: EQ4/musicd
static int64_t scan_file(const char *path, int64_t directory)
{
  const char *extension;
  int64_t file = 0;
  track_t **tracks;
  int i;

  for (extension = path + strlen(path);
    *(extension) != '.' && extension != path; --extension) { }
  ++extension;
    
  if (!strcasecmp(extension, "cue")) {
    /* CUE sheet */
    musicd_log(LOG_DEBUG, "scan", "cue: %s", path);
    cue_read(path, directory);
  } else if(FreeImage_GetFIFFromFilename(path) != FIF_UNKNOWN) {
    /* Image file */
    if (FreeImage_GetFileType(path, 0) != FIF_UNKNOWN) {
      musicd_log(LOG_DEBUG, "scan", "image: %s", path);
      file = library_file(path, directory);
      library_image_add(file);
    }
  } else {
    tracks = tracks_from_path(path);
    /* Try tracks */
    if (!tracks) {
      return file;
    }
    for (i = 0; tracks[i]; ++i) {
      musicd_log(LOG_DEBUG, "scan", "track: %s", path);
      library_track_add(tracks[i], directory);
      scan_track_added();
      file = library_file(path, 0);
    }
    tracks_free(tracks);
  } 
  return file;
}
示例#22
0
int query_start(query_t *query)
{
  string_t *sql = string_new();
  char *where = build_filters(query);
  sqlite3_stmt *stmt;

  string_append(sql, query->format->body);
  string_append(sql, query->format->from);
  string_append(sql, query->format->join);
  string_append(sql, where);
  free(where);

  if (string_size(query->order) > 0) {
    string_appendf(sql, " ORDER BY %s", string_string(query->order));
  }

  if (query->limit > 0 || query->offset > 0) {
    string_appendf(sql, " LIMIT %" PRId64 " OFFSET %" PRId64 "", query->limit, query->offset);
  }

  musicd_log(LOG_DEBUG, "query", "%s", string_string(sql));

  if (sqlite3_prepare_v2(db_handle(),
                         string_string(sql), -1,
                         &stmt, NULL) != SQLITE_OK) {
    musicd_log(LOG_ERROR, "query", "can't prepare '%s': %s",
               string_string(sql), db_error());
    string_free(sql);
    return -1;
  }
  string_free(sql);

  bind_filters(query, stmt);

  query->stmt = stmt;

  return 0;
}
示例#23
0
文件: library.c 项目: EQ4/musicd
static int64_t execute_scalar(sqlite3_stmt *query)
{
  int64_t result = sqlite3_step(query);
  if (result == SQLITE_ROW) {
    result = sqlite3_column_int(query, 0);
  } else if (result == SQLITE_DONE) {
    result = 0;
  } else {
    musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'",
               sqlite3_sql(query));
    result = -1;
  }
  sqlite3_finalize(query);
  return result;
}
示例#24
0
文件: library.c 项目: EQ4/musicd
lyrics_t *library_lyrics(int64_t track, time_t *time)
{
  static const char *sql =
    "SELECT lyrics, provider, source, mtime FROM lyrics WHERE trackid = ?";
  sqlite3_stmt *query;
  int result;
  lyrics_t *lyrics;

  if (time) {
    *time = 0;
  }

  if (!prepare_query(sql, &query)) {
    return NULL;
  }
  
  sqlite3_bind_int64(query, 1, track);
  
  result = sqlite3_step(query);
  if (result != SQLITE_DONE && result != SQLITE_ROW) {
    musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql);
  }
  if (result == SQLITE_ROW) {
    if (time) {
      *time = sqlite3_column_int64(query, 3);
    }
    if (!sqlite3_column_text(query, 0)) {
      return NULL;
    }

    lyrics = lyrics_new();
    lyrics->lyrics = strcopy((const char *)sqlite3_column_text(query, 0));
    if (sqlite3_column_text(query, 1)) {
      lyrics->provider = strcopy((const char *)sqlite3_column_text(query, 1));
    }
    if (sqlite3_column_text(query, 2)) {
      lyrics->source = strcopy((const char *)sqlite3_column_text(query, 2));
    }
    return lyrics;
  }
  return NULL;
}
示例#25
0
文件: client.c 项目: EQ4/musicd
static int read_data(client_t *client)
{
  char buffer[1025];
  int n;

  n = read(client->fd, buffer, 1024);
  if (n == 0) {
    musicd_log(LOG_INFO, "client", "%s: exiting", client->address);
    return -1;
  }
  if (n < 0) {
    if (errno == EWOULDBLOCK) {
      /* No data available right now, ignore */
      return 0;
    }

    musicd_perror(LOG_INFO, "client", "%s: can't read", client->address);
    return -1;
  }

  string_nappend(client->inbuf, buffer, n);

  return n;
}
示例#26
0
文件: stream.c 项目: EQ4/musicd
static int read_next(stream_t *stream)
{
  int result;
  
  while (1) {
    av_free_packet(&stream->src_packet);

    result = av_read_frame(stream->src_ctx, &stream->src_packet);
    if (result < 0) {
      if (result == AVERROR_EOF) {
        /* end of file */
        return 0;
      }
      musicd_log(LOG_ERROR, "stream", "av_read_frame failed: %s",
                 strerror(AVUNERROR(result)));
      return 0;
    }

    if (stream->src_packet.stream_index != 0) {
      continue;
    }
    break;
  }

  if (stream->src_packet.pts * av_q2d(stream->src_ctx->streams[0]->time_base) >
      stream->track->start + stream->track->duration) {
    if (stream->track->cuefile) {
      /* Accurate end of track */
      return 0;
    } else {
      /* Miscalculated track length */
    }
  }
  
  return 1;
}
示例#27
0
文件: stream.c 项目: EQ4/musicd
static int encode_next(stream_t *stream)
{
  int result, got_packet;
  AVFrame *frame = stream->encode_frame;
  AVPacket *packet = &stream->encode_packet;

  while (av_audio_fifo_size(stream->src_buf) < stream->encoder->frame_size) {
    result = decode_next(stream);
    if (result <= 0) {
      return result;
    }
  }

  av_audio_fifo_read(stream->src_buf,
                     (void **)frame->extended_data,
                     stream->encoder->frame_size);

  av_free_packet(packet);

  result = avcodec_encode_audio2(stream->encoder, packet, frame, &got_packet);

  if (result < 0) {
    musicd_log(LOG_ERROR, "stream", "can't encode: %s",
               strerror(AVUNERROR(result)));
    return -1;
  }

  if (!got_packet) {
    return 1;
  }

  stream->dst_data = packet->data;
  stream->dst_size = packet->size;

  return 1;
}
示例#28
0
文件: cue.c 项目: EQ4/musicd
/**
 * @todo FIXME Multiple files in same cue sheet
 * @todo FIXME Rewrite this garbage
 */
bool cue_read(const char *cuepath, int64_t directory)
{
  bool result = true;
  
  FILE *file;
  char *directory_path, *path, *path2;
  
  bool header_read = false;
  
  char album[512], albumartist[512];
  char line[1024], instr[16], string1[512], *ptr;
  
  int64_t track_file;
  
  struct stat status;
  
  //char file[strlen(path) + 1024 + 2], cuefile[strlen(path) + 1024 + 2];
  
  int i;
  
  int index, mins, secs, frames;
  /* Track is stored in prev_track until index of the following track is known.
   * This is mandatory for figuring out the track's length. Last track's
   * length is calculated from file's total length. */
  track_t *prev_track = NULL, *track = NULL, *file_track = NULL;
  
  file = fopen(cuepath, "r");
  if (!file) {
    musicd_perror(LOG_ERROR, "cue", "can't open file %s", cuepath);
    return false;
  }
  
  directory_path = malloc(strlen(cuepath));
  
  /* Extract directory path. */
  for (i = strlen(cuepath) - 1; i > 0 && cuepath[i] != '/'; --i) { }
  strncpy(directory_path, cuepath, i);
  directory_path[i] = '\0';
  
  /* Directory + 256 4-byte UTF-8 characters + '/' + '\0', more than needed. */
  path = malloc(strlen(directory_path) + 1024 + 2);
  path2 = malloc(strlen(directory_path) + 1024 + 2);
  
  album[0] = '\0';
  albumartist[0] = '\0';
  
  /* Check for BOM, seek back if not found. */
  fread(line, 1, 3, file);
  if (line[0] != (char)0xef
   || line[1] != (char)0xbb
   || line[2] != (char)0xbf) {
    fseek(file, 0, SEEK_SET);
  }

  while (read_line(file, line, sizeof(line))) {
    /* Read instruction, up to 15 characters. */
    if (sscanf(line, "%15s", instr) < 1) {
      continue;
    }
    
    
    /* Skip comments. */
    if (!strcmp(instr, "REM")) {
      continue;
    }
    
    ptr = line + strlen(instr) + 1;
    if (ptr[0] == '"') {
      ptr += read_string(ptr, string1) + 1;
    }
    
    if (!strcmp(instr, "PERFORMER")) {
      /*musicd_log(LOG_DEBUG, "cue", "performer: %s", string1);*/
      if (!header_read) {
        strcpy(albumartist, string1);
      } else if (track) {
        free(track->artist);
        track->artist = strcopy(string1);
      }
    } else if (!strcmp(instr, "TITLE")) {
      /*musicd_log(LOG_DEBUG, "cue", "title: %s", string1);*/
      if (!header_read) {
        strcpy(album, string1);
      } else if (track) {
        free(track->title);
        track->title = strcopy(string1);
      }
    } else if (!strcmp(instr, "FILE")) {
      if (file_track) {
        musicd_log(LOG_WARNING, "cue", "multiple FILEs in a single cue sheet"
                                       "(%s) is currently unsupported, sorry",
                                        cuepath);
        break;
      }
      
      header_read = true;
      
      sprintf(path, "%s/%s", directory_path, string1);
      
      if (stat(path, &status)) {
        result = false;
        break;
      }
      
      /* Prioritizing: if there are multiple cue sheets and a cue sheet with
       * same base name as the track file exists, it is used for the track.
       * otherwise, sheet with highest mtime will result to be selected.
       */
      for (i = strlen(path) - 1; i > 0 && path[i] != '.'; --i) { }
      strncpy(path2, path, i);
      strcpy(path2 + i, ".cue");
      
      if (strcmp(path2, cuepath) && stat(path2, &status) == 0) {
        musicd_log(LOG_DEBUG, "cue",
                   "multiple cue sheets for '%s', trying '%s'",
                   path, path2);
        if (cue_read(path2, directory)) {
          break;
        }
      }
      
      file_track = track_from_path(path);
      if (!file_track) {
        break;
      }
      
      track_file = library_file(path, 0);
      if (track_file > 0) {
        /* File already exists, clear associated tracks. */
        library_file_clear(track_file);
      } else {
        track_file = library_file(path, directory);
        if (track_file <= 0) {
          /* Some error... */
          break;
        }
      }
      
      library_file_mtime_set(track_file, status.st_mtime);
      
      musicd_log(LOG_DEBUG, "cue", "audio: %s", path);
      continue;
    }
    
    
    if (!file_track) {
      continue;
    }
    
    if (!strcmp(instr, "TRACK")) {
      sscanf(ptr, "%d %s", &index, string1);
      /*musicd_log(LOG_DEBUG, "cue", "track: %d '%s'", index, string1);*/
      if (track) {
        if (!prev_track) {
          prev_track = track;
        } else {
          prev_track->duration = track->start - prev_track->start;
          library_track_add(prev_track, directory);
          scan_track_added();
          track_free(prev_track);
          prev_track = track;
        }
      }
      
      track = track_new();
      track->cuefile = strcopy(cuepath);
      track->file = strcopy(path);
      track->track = index;
      /* Set artist same as the album artist and replace if track spefific
       * artist is later defined. */
      track->artist = strcopy(albumartist);
      track->album = strcopy(album);
      track->albumartist = strcopy(albumartist);
    }
    
    if (!strcmp(instr, "INDEX")) {
      sscanf(ptr, "%d %d:%d:%d", &index, &mins, &secs, &frames);
      /*musicd_log(LOG_DEBUG, "cue", "index: %d %2.2d:%2.2d.%2.2d", index, mins, secs, frames);*/
      if (index == 1) {
        /* One frame is 1/75 seconds */
        track->start = mins * 60.0 + secs + frames / 75.0;
      }
    }    
    
  }
  
  if (prev_track) {
    prev_track->duration = track->start - prev_track->start;
    library_track_add(prev_track, directory);
    scan_track_added();
    track_free(prev_track);
  }
  if (track) {
    track->duration = file_track->duration - track->start;
    library_track_add(track, directory);
    scan_track_added();
    track_free(track);
  }
  
  track_free(file_track);
  
  fclose(file);
  
  free(directory_path);
  
  free(path);
  free(path2);
  
  return result;
}
示例#29
0
文件: client.c 项目: EQ4/musicd
int client_process(client_t *client)
{
  int result;

  while ((result = read_data(client)) > 0) { }
  if (result < 0) {
    return result;
  }

  if (!client->protocol) {
    /* The client has no protocol detected yet */

    find_protocol(client);

    if (!client->protocol) {
      musicd_log(LOG_ERROR, "client", "%s: unknown protocol, terminating",
                 client->address);
      return -1;
    }
    
    musicd_log(LOG_DEBUG, "client", "%s: protocol is '%s'",
                          client->address, client->protocol->name);
    
    /* Actually open the client to be processed with detected protocol */
    client->self = client->protocol->open(client);
  }

  if (client->state == CLIENT_STATE_WAIT_TASK) {
    /* Client was waiting for task to finish and now the task manager signaled
     * through the pipe. */
    client->state = CLIENT_STATE_NORMAL;
    task_free(client->wait_task);
    if (client->wait_callback(client->self, client->wait_data) < 0) {
      return -1;
    }
  }

  /* (Try to) purge the entire outgoing buffer. */

  if (string_size(client->outbuf) > 0) {
    /* There is outgoing data in buffer, try to write */
    result = write_data(client);
    if (result < 0) {
      return result;
    }
  }

  if (client->state == CLIENT_STATE_DRAIN) {
    if (string_size(client->outbuf) == 0) {
      /* Client was draining, and now it is done - terminate */
      return -1;
    }
  }

  /* If there was nothing to write but we have unprocessed data, process it. */

  if (string_size(client->inbuf) > 0) {
    result = client->protocol->process(client->self,
                                      string_string(client->inbuf),
                                      string_size(client->inbuf));
    if (result < 0) {
      return result;
    }

    string_remove_front(client->inbuf, result);
  } else if (client->state == CLIENT_STATE_FEED
          && string_size(client->outbuf) == 0) {

    /* There wasn't anything to process, we can push data to the client and the
     * outgoing buffer is empty. */

    result = client->protocol->feed(client->self);
    if (result < 0) {
      return result;
    }
  }

  return 0;
}
示例#30
0
文件: musicd.c 项目: EQ4/musicd
int main(int argc, char* argv[])
{ 
  musicd_start_time = time(NULL);

  config_init();

  config_set_hook("log-level", log_level_changed);
  config_set_hook("log-time-format", log_time_format_changed);
  config_set("log-level", "debug");

  config_set_hook("directory", directory_changed);
  
  config_set("config", "~/.musicd.conf");
  config_set("directory", "~/.musicd");
  config_set("bind", "any");
  config_set("port", "6800");
  
  config_set_hook("image-prefix", scan_image_prefix_changed);
  config_set("image-prefix", "front,cover,jacket");

  config_set("server-name", "musicd server");

  if (config_load_args(argc, argv)) {
    musicd_log(LOG_FATAL, "main", "invalid command line arguments");
    print_usage(argv[0]);
    return -1;
  }
  
  if (config_get_value("help")) {
    print_usage(argv[0]);
    return 0;
  }
  if (config_get_value("version")) {
    print_version();
    return 0;
  }
  
  if (!config_to_bool("no-config")
   && config_load_file(config_to_path("config"))) {
    musicd_log(LOG_FATAL, "main", "could not read config file");
    return -1;
  }
  
  /* Reload command line arguments - this is because the config file might have
   * overwritten them, and the command line has the highest priority. */
  config_load_args(argc, argv);
  
  confirm_directory();
  
  musicd_log(LOG_INFO, "main", "musicd version %s", MUSICD_VERSION_STRING);
  
  srand(time(NULL));

  av_register_all();
  avcodec_register_all();
  av_lockmgr_register(&musicd_av_lockmgr);
  
  av_log_set_level(AV_LOG_QUIET);

  if (db_open()) {
    musicd_log(LOG_FATAL, "library", "can't open database");
    return -1;
  }

  if (library_open()) {
    musicd_log(LOG_FATAL, "main", "could not open library");
    return -1;
  }
  
  if (cache_open()) {
    musicd_log(LOG_FATAL, "main", "could not open cache");
    return -1;
  }
  
  if (server_start()) {
    musicd_log(LOG_FATAL, "main", "could not start server");
    return -1;
  }
  
  signal(SIGUSR1, start_scan_signal);
  scan_start();
  
  while (1) {
    sleep(1);
  }
  
  return 0;
}