+static int loglevel;
+INIT_STDERR_LOGGING(loglevel)
+
+static void print_info(int audio_format_num, struct afh_info *afhi)
+{
+ printf("%s: %dkbit/s\n" /* bitrate */
+ "%s: %s\n" /* format */
+ "%s: %dHz\n" /* frequency */
+ "%s: %d\n" /* channels */
+ "%s: %lu\n" /* seconds total */
+ "%s: %lu: %lu\n" /* chunk time */
+ "%s: %lu\n" /* num chunks */
+ "%s: %s\n" /* techinfo */
+ "%s: %s\n" /* artist */
+ "%s: %s\n" /* title */
+ "%s: %s\n" /* year */
+ "%s: %s\n" /* album */
+ "%s: %s\n", /* comment */
+ status_item_list[SI_BITRATE], afhi->bitrate,
+ status_item_list[SI_FORMAT], audio_format_name(audio_format_num),
+ status_item_list[SI_FREQUENCY], afhi->frequency,
+ status_item_list[SI_CHANNELS], afhi->channels,
+ status_item_list[SI_SECONDS_TOTAL], afhi->seconds_total,
+ status_item_list[SI_CHUNK_TIME], (long unsigned)afhi->chunk_tv.tv_sec,
+ (long unsigned)afhi->chunk_tv.tv_usec,
+ status_item_list[SI_NUM_CHUNKS], afhi->chunks_total,
+ status_item_list[SI_TECHINFO], afhi->techinfo? afhi->techinfo : "",
+ status_item_list[SI_ARTIST], afhi->tags.artist? afhi->tags.artist : "",
+ status_item_list[SI_TITLE], afhi->tags.title? afhi->tags.title : "",
+ status_item_list[SI_YEAR], afhi->tags.year? afhi->tags.year : "",
+ status_item_list[SI_ALBUM], afhi->tags.album? afhi->tags.album : "",
+ status_item_list[SI_COMMENT], afhi->tags.comment? afhi->tags.comment : ""
+ );
+}
+
+static void print_chunk_table(struct afh_info *afhi)
+{
+ int i;
+
+ if (!conf.human_given) {
+ printf("chunk_table: ");
+ for (i = 0; i <= afhi->chunks_total; i++)
+ printf("%u ", afhi->chunk_table[i]);
+ printf("\n");
+ return;
+ }
+ for (i = 1; i <= afhi->chunks_total; i++) {
+ struct timeval tv;
+ long unsigned from, to;
+ tv_scale(i - 1, &afhi->chunk_tv, &tv);
+ from = tv2ms(&tv);
+ tv_scale(i, &afhi->chunk_tv, &tv);
+ to = tv2ms(&tv);
+ printf("%d [%lu.%03lu - %lu.%03lu] %u - %u (%u)\n", i - 1,
+ from / 1000, from % 1000, to / 1000, to % 1000,
+ afhi->chunk_table[i - 1], afhi->chunk_table[i],
+ afhi->chunk_table[i] - afhi->chunk_table[i - 1]);
+ }
+}
+
+static int cat_file(void *audio_file_data, struct afh_info *afhi)
+{
+ int ret;
+ struct timeval stream_start;
+ long unsigned i, first_chunk, last_chunk;
+ const char *buf;
+ size_t size;
+
+
+ if (conf.begin_chunk_arg < 0) {
+ if (-conf.begin_chunk_arg > afhi->chunks_total)
+ return -ERRNO_TO_PARA_ERROR(EINVAL);
+ first_chunk = afhi->chunks_total + conf.begin_chunk_arg;
+ } else
+ first_chunk = conf.begin_chunk_arg;
+ if (conf.end_chunk_given) {
+ if (conf.end_chunk_arg < 0) {
+ if (-conf.end_chunk_arg > afhi->chunks_total)
+ return -ERRNO_TO_PARA_ERROR(EINVAL);
+ last_chunk = afhi->chunks_total + conf.end_chunk_arg;
+ } else {
+ if (conf.end_chunk_arg >= afhi->chunks_total)
+ return -ERRNO_TO_PARA_ERROR(EINVAL);
+ last_chunk = conf.end_chunk_arg;
+ }
+ } else
+ last_chunk = afhi->chunks_total - 1;
+ if (first_chunk >= last_chunk)
+ return -ERRNO_TO_PARA_ERROR(EINVAL);
+ if (!afhi->chunks_total)
+ return 1;
+ afh_get_header(afhi, audio_file_data, &buf, &size);
+ if (size && first_chunk && !conf.no_header_given) {
+ PARA_INFO_LOG("writing audio file header (%zu bytes)\n", size);
+ ret = write(STDOUT_FILENO, buf, size);
+ if (ret < 0)
+ return ret;
+ if (ret != size)
+ return -E_AFH_SHORT_WRITE;
+ }
+ PARA_NOTICE_LOG("writing chunks %lu - %lu\n", first_chunk, last_chunk);
+ gettimeofday(&stream_start, NULL);
+ for (i = first_chunk; i <= last_chunk; i++) {
+ struct timeval now, diff, next_chunk;
+ afh_get_chunk(i, afhi, audio_file_data, &buf, &size);
+ PARA_DEBUG_LOG("chunk %lu: size %zu\n", i, size);
+ if (conf.just_in_time_given) {
+ compute_chunk_time(i - first_chunk, &afhi->chunk_tv,
+ &stream_start, &next_chunk);
+ gettimeofday(&now, NULL);
+ ret = tv_diff(&next_chunk, &now, &diff);
+ if (ret > 0) {
+ ret = para_select(1, NULL, NULL, &diff);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ if (!size)
+ continue;
+ PARA_INFO_LOG("writing chunk %lu\n", i);
+ ret = write_all(STDOUT_FILENO, buf, &size);
+ if (ret < 0)
+ return ret;
+ }
+ return 1;
+}
+
+/**
+ * The main function of para_afh.
+ *
+ * \param argc Usual argument count.
+ * \param argv Usual argument vector.
+ *
+ * \return \p EXIT_FAILURE or \p EXIT_SUCCESS.
+ */