Add Russian translation provided by Валерий Крувялис <valkru@mail.ru>
[xiph-mirror.git] / vorbis-tools / ogg123 / status.c
blob24b37720b70168b6ca1d0bd309d0d3ce4487da53
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
6 * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2001 *
9 * by Stan Seibert <volsung@xiph.org> AND OTHER CONTRIBUTORS *
10 * http://www.xiph.org/ *
11 * *
12 ********************************************************************
14 last mod: $Id$
16 ********************************************************************/
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <pthread.h>
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
30 #ifdef HAVE_FCNTL_H
31 #include <fcntl.h>
32 #endif
34 #include "status.h"
35 #include "i18n.h"
37 char temp_buffer[200];
38 int last_line_len = 0;
39 int max_verbosity = 0;
40 int exit_status = EXIT_SUCCESS;
42 pthread_mutex_t output_lock = PTHREAD_MUTEX_INITIALIZER;
45 /* ------------------- Private functions ------------------ */
47 void unlock_output_lock (void *arg)
49 pthread_mutex_unlock(&output_lock);
53 void write_buffer_state_string (char *dest, buffer_stats_t *buf_stats)
55 char *cur = dest;
56 char *comma = ", ";
57 char *sep = "(";
59 if (buf_stats->prebuffering) {
60 cur += sprintf (cur, _("%sPrebuf to %.1f%%"), sep,
61 100.0f * buf_stats->prebuffer_fill);
62 sep = comma;
64 if (buf_stats->paused) {
65 cur += sprintf (cur, _("%sPaused"), sep);
66 sep = comma;
68 if (buf_stats->eos) {
69 cur += sprintf (cur, _("%sEOS"), sep);
70 sep = comma;
72 if (cur != dest)
73 cur += sprintf (cur, ")");
74 else
75 *cur = '\0';
79 /* Write a min:sec.msec style string to dest corresponding to time.
80 The time parameter is in seconds. Returns the number of characters
81 written */
82 int write_time_string (char *dest, double time)
84 long min = (long) time / (long) 60;
85 double sec = time - 60.0f * min;
87 return sprintf (dest, "%02li:%05.2f", min, sec);
91 void clear_line (int len)
93 fputc('\r', stderr);
95 while (len > 0) {
96 fputc (' ', stderr);
97 len--;
100 fputc ('\r', stderr);
104 int sprintf_clear_line(int len, char *buf)
106 int i = 0;
108 buf[i] = '\r';
109 i++;
111 while (len > 0) {
112 buf[i] = ' ';
113 len--;
114 i++;
117 buf[i] = '\r';
118 i++;
120 /* Null terminate just in case */
121 buf[i] = '\0';
123 return i;
126 int print_statistics_line (stat_format_t stats[])
128 int len = 0;
129 char *str = temp_buffer;
131 if (max_verbosity == 0)
132 return 0;
134 /* Put the clear line text into the same string buffer so that the
135 line is cleared and redrawn all at once. This reduces
136 flickering. Don't count characters used to clear line in len */
137 str += sprintf_clear_line(last_line_len, str);
139 while (stats->formatstr != NULL) {
141 if (stats->verbosity > max_verbosity || !stats->enabled) {
142 stats++;
143 continue;
146 if (len != 0)
147 len += sprintf(str+len, " ");
149 switch (stats->type) {
150 case stat_noarg:
151 len += sprintf(str+len, "%s", stats->formatstr);
152 break;
153 case stat_intarg:
154 len += sprintf(str+len, stats->formatstr, stats->arg.intarg);
155 break;
156 case stat_stringarg:
157 len += sprintf(str+len, stats->formatstr, stats->arg.stringarg);
158 break;
159 case stat_floatarg:
160 len += sprintf(str+len, stats->formatstr, stats->arg.floatarg);
161 break;
162 case stat_doublearg:
163 len += sprintf(str+len, stats->formatstr, stats->arg.doublearg);
164 break;
167 stats++;
170 len += sprintf(str+len, "\r");
172 fprintf(stderr, "%s", temp_buffer);
174 return len;
178 void vstatus_print_nolock (const char *fmt, va_list ap)
180 if (last_line_len != 0)
181 fputc ('\n', stderr);
183 vfprintf (stderr, fmt, ap);
185 fputc ('\n', stderr);
187 last_line_len = 0;
191 /* ------------------- Public interface -------------------- */
193 #define TIME_STR_SIZE 20
194 #define STATE_STR_SIZE 25
195 #define NUM_STATS 10
197 stat_format_t *stat_format_create ()
199 stat_format_t *stats;
200 stat_format_t *cur;
202 stats = calloc(NUM_STATS + 1, sizeof(stat_format_t)); /* One extra for end flag */
203 if (stats == NULL) {
204 fprintf(stderr, _("Memory allocation error in stats_init()\n"));
205 exit(1);
208 cur = stats + 0; /* currently playing file / stream */
209 cur->verbosity = 3;
210 cur->enabled = 0;
211 cur->formatstr = _("File: %s");
212 cur->type = stat_stringarg;
214 cur = stats + 1; /* current playback time (preformatted) */
215 cur->verbosity = 1;
216 cur->enabled = 1;
217 cur->formatstr = _("Time: %s");
218 cur->type = stat_stringarg;
219 cur->arg.stringarg = calloc(TIME_STR_SIZE, sizeof(char));
221 if (cur->arg.stringarg == NULL) {
222 fprintf(stderr, _("Memory allocation error in stats_init()\n"));
223 exit(1);
225 write_time_string(cur->arg.stringarg, 0.0);
228 cur = stats + 2; /* remaining playback time (preformatted) */
229 cur->verbosity = 1;
230 cur->enabled = 1;
231 cur->formatstr = "[%s]";
232 cur->type = stat_stringarg;
233 cur->arg.stringarg = calloc(TIME_STR_SIZE, sizeof(char));
235 if (cur->arg.stringarg == NULL) {
236 fprintf(stderr, _("Memory allocation error in stats_init()\n"));
237 exit(1);
239 write_time_string(cur->arg.stringarg, 0.0);
242 cur = stats + 3; /* total playback time (preformatted) */
243 cur->verbosity = 1;
244 cur->enabled = 1;
245 cur->formatstr = _("of %s");
246 cur->type = stat_stringarg;
247 cur->arg.stringarg = calloc(TIME_STR_SIZE, sizeof(char));
249 if (cur->arg.stringarg == NULL) {
250 fprintf(stderr, _("Memory allocation error in stats_init()\n"));
251 exit(1);
253 write_time_string(cur->arg.stringarg, 0.0);
256 cur = stats + 4; /* instantaneous bitrate */
257 cur->verbosity = 2;
258 cur->enabled = 1;
259 cur->formatstr = " (%5.1f kbps)";
260 cur->type = stat_doublearg;
262 cur = stats + 5; /* average bitrate (not yet implemented) */
263 cur->verbosity = 2;
264 cur->enabled = 0;
265 cur->formatstr = _("Avg bitrate: %5.1f");
266 cur->type = stat_doublearg;
268 cur = stats + 6; /* input buffer fill % */
269 cur->verbosity = 2;
270 cur->enabled = 0;
271 cur->formatstr = _(" Input Buffer %5.1f%%");
272 cur->type = stat_doublearg;
274 cur = stats + 7; /* input buffer status */
275 cur->verbosity = 2;
276 cur->enabled = 0;
277 cur->formatstr = "%s";
278 cur->type = stat_stringarg;
279 cur->arg.stringarg = calloc(STATE_STR_SIZE, sizeof(char));
281 if (cur->arg.stringarg == NULL) {
282 fprintf(stderr, _("Memory allocation error in stats_init()\n"));
283 exit(1);
287 cur = stats + 8; /* output buffer fill % */
288 cur->verbosity = 2;
289 cur->enabled = 0;
290 cur->formatstr = _(" Output Buffer %5.1f%%");
291 cur->type = stat_doublearg;
293 cur = stats + 9; /* output buffer status */
294 cur->verbosity = 1;
295 cur->enabled = 0;
296 cur->formatstr = "%s";
297 cur->type = stat_stringarg;
298 cur->arg.stringarg = calloc(STATE_STR_SIZE, sizeof(char));
300 if (cur->arg.stringarg == NULL) {
301 fprintf(stderr, _("Memory allocation error in stats_init()\n"));
302 exit(1);
306 cur = stats + 10; /* End flag */
307 cur->formatstr = NULL;
309 return stats;
313 void stat_format_cleanup (stat_format_t *stats)
315 free(stats[1].arg.stringarg);
316 free(stats[2].arg.stringarg);
317 free(stats[3].arg.stringarg);
318 free(stats[7].arg.stringarg);
319 free(stats[9].arg.stringarg);
320 free(stats);
324 void status_init (int verbosity)
326 #if defined(HAVE_FCNTL) && defined(HAVE_UNISTD_H)
327 fcntl (STDERR_FILENO, F_SETFL, fcntl(STDERR_FILENO, F_GETFL) | O_NONBLOCK);
328 #endif
330 max_verbosity = verbosity;
333 void status_deinit ()
335 #if defined(HAVE_FCNTL) && defined(HAVE_UNISTD_H)
336 fcntl (STDERR_FILENO, F_SETFL, fcntl(STDERR_FILENO, F_GETFL) & ~O_NONBLOCK);
337 #endif
340 void status_reset_output_lock ()
342 pthread_mutex_unlock(&output_lock);
346 void status_clear_line ()
348 pthread_cleanup_push(unlock_output_lock, NULL);
350 pthread_mutex_lock(&output_lock);
351 clear_line(last_line_len);
352 pthread_mutex_unlock(&output_lock);
354 pthread_cleanup_pop(0);
357 void status_print_statistics (stat_format_t *stats,
358 buffer_stats_t *audio_statistics,
359 data_source_stats_t *transport_statistics,
360 decoder_stats_t *decoder_statistics)
362 pthread_cleanup_push(unlock_output_lock, NULL);
364 /* Updating statistics is not critical. If another thread is
365 already doing output, we skip it. */
366 if (pthread_mutex_trylock(&output_lock) == 0) {
368 if (decoder_statistics != NULL) {
369 /* Current playback time */
370 write_time_string(stats[1].arg.stringarg,
371 decoder_statistics->current_time);
373 /* Remaining playback time */
374 write_time_string(stats[2].arg.stringarg,
375 decoder_statistics->total_time -
376 decoder_statistics->current_time);
378 /* Total playback time */
379 write_time_string(stats[3].arg.stringarg,
380 decoder_statistics->total_time);
382 /* Instantaneous bitrate */
383 stats[4].arg.doublearg = decoder_statistics->instant_bitrate / 1000.0f;
385 /* Instantaneous bitrate */
386 stats[5].arg.doublearg = decoder_statistics->avg_bitrate / 1000.0f;
390 if (transport_statistics != NULL &&
391 transport_statistics->input_buffer_used) {
393 /* Input buffer fill % */
394 stats[6].arg.doublearg = transport_statistics->input_buffer.fill;
396 /* Input buffer state */
397 write_buffer_state_string(stats[7].arg.stringarg,
398 &transport_statistics->input_buffer);
402 if (audio_statistics != NULL) {
404 /* Output buffer fill % */
405 stats[8].arg.doublearg = audio_statistics->fill;
407 /* Output buffer state */
408 write_buffer_state_string(stats[9].arg.stringarg, audio_statistics);
411 last_line_len = print_statistics_line(stats);
413 pthread_mutex_unlock(&output_lock);
416 pthread_cleanup_pop(0);
420 void status_message (int verbosity, const char *fmt, ...)
422 va_list ap;
424 if (verbosity > max_verbosity)
425 return;
427 pthread_cleanup_push(unlock_output_lock, NULL);
429 pthread_mutex_lock(&output_lock);
431 clear_line(last_line_len);
433 va_start (ap, fmt);
434 vstatus_print_nolock(fmt, ap);
435 va_end (ap);
437 pthread_mutex_unlock(&output_lock);
439 pthread_cleanup_pop(0);
443 void vstatus_message (int verbosity, const char *fmt, va_list ap)
445 if (verbosity > max_verbosity)
446 return;
448 pthread_cleanup_push(unlock_output_lock, NULL);
450 pthread_mutex_lock(&output_lock);
452 clear_line(last_line_len);
453 vstatus_print_nolock(fmt, ap);
455 pthread_mutex_unlock(&output_lock);
457 pthread_cleanup_pop(0);
461 void status_error (const char *fmt, ...)
463 va_list ap;
465 pthread_cleanup_push(unlock_output_lock, NULL);
467 pthread_mutex_lock(&output_lock);
468 va_start (ap, fmt);
469 clear_line(last_line_len);
470 vstatus_print_nolock (fmt, ap);
471 va_end (ap);
472 pthread_mutex_unlock(&output_lock);
474 pthread_cleanup_pop(0);
476 exit_status = EXIT_FAILURE;
480 void vstatus_error (const char *fmt, va_list ap)
482 pthread_cleanup_push(unlock_output_lock, NULL);
484 pthread_mutex_lock(&output_lock);
485 clear_line(last_line_len);
486 vstatus_print_nolock (fmt, ap);
487 pthread_mutex_unlock(&output_lock);
489 pthread_cleanup_pop(0);
491 exit_status = EXIT_FAILURE;