1 /********************************************************************
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. *
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/ *
12 ********************************************************************
14 last mod: $Id: status.c,v 1.8 2002/03/19 09:50:09 msmith Exp $
16 ********************************************************************/
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
)
59 if (buf_stats
->prebuffering
) {
60 cur
+= sprintf (cur
, _("%sPrebuf to %.1f%%"), sep
,
61 100.0f
* buf_stats
->prebuffer_fill
);
64 if (buf_stats
->paused
) {
65 cur
+= sprintf (cur
, _("%sPaused"), sep
);
69 cur
+= sprintf (cur
, _("%sEOS"), sep
);
73 cur
+= sprintf (cur
, ")");
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
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
)
100 fputc ('\r', stderr
);
104 int sprintf_clear_line(int len
, char *buf
)
120 /* Null terminate just in case */
126 int print_statistics_line (stat_format_t stats
[])
129 char *str
= temp_buffer
;
131 if (max_verbosity
== 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
) {
147 len
+= sprintf(str
+len
, " ");
149 switch (stats
->type
) {
151 len
+= sprintf(str
+len
, stats
->formatstr
);
154 len
+= sprintf(str
+len
, stats
->formatstr
, stats
->arg
.intarg
);
157 len
+= sprintf(str
+len
, stats
->formatstr
, stats
->arg
.stringarg
);
160 len
+= sprintf(str
+len
, stats
->formatstr
, stats
->arg
.floatarg
);
163 len
+= sprintf(str
+len
, stats
->formatstr
, stats
->arg
.doublearg
);
170 len
+= sprintf(str
+len
, "\r");
172 fprintf(stderr
, "%s", temp_buffer
);
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
);
191 /* ------------------- Public interface -------------------- */
193 #define TIME_STR_SIZE 20
194 #define STATE_STR_SIZE 25
197 stat_format_t
*stat_format_create ()
199 stat_format_t
*stats
;
202 stats
= calloc(NUM_STATS
+ 1, sizeof(stat_format_t
)); /* One extra for end flag */
204 fprintf(stderr
, _("Memory allocation error in stats_init()\n"));
208 cur
= stats
+ 0; /* currently playing file / stream */
211 cur
->formatstr
= _("File: %s");
212 cur
->type
= stat_stringarg
;
214 cur
= stats
+ 1; /* current playback time (preformatted) */
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"));
225 write_time_string(cur
->arg
.stringarg
, 0.0);
228 cur
= stats
+ 2; /* remaining playback time (preformatted) */
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"));
239 write_time_string(cur
->arg
.stringarg
, 0.0);
242 cur
= stats
+ 3; /* total playback time (preformatted) */
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"));
253 write_time_string(cur
->arg
.stringarg
, 0.0);
256 cur
= stats
+ 4; /* instantaneous bitrate */
259 cur
->formatstr
= " (%5.1f kbps)";
260 cur
->type
= stat_doublearg
;
262 cur
= stats
+ 5; /* average bitrate (not yet implemented) */
265 cur
->formatstr
= _("Avg bitrate: %5.1f");
266 cur
->type
= stat_doublearg
;
268 cur
= stats
+ 6; /* input buffer fill % */
271 cur
->formatstr
= _(" Input Buffer %5.1f%%");
272 cur
->type
= stat_doublearg
;
274 cur
= stats
+ 7; /* input buffer status */
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"));
287 cur
= stats
+ 8; /* output buffer fill % */
290 cur
->formatstr
= _(" Output Buffer %5.1f%%");
291 cur
->type
= stat_doublearg
;
293 cur
= stats
+ 9; /* output buffer status */
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"));
306 cur
= stats
+ 10; /* End flag */
307 cur
->formatstr
= NULL
;
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
);
324 void status_init (int verbosity
)
326 #if defined(HAVE_FCNTL) && defined(HAVE_UNISTD_H)
327 fcntl (STDERR_FILENO
, F_SETFL
, O_NONBLOCK
);
330 max_verbosity
= verbosity
;
334 void status_reset_output_lock ()
336 pthread_mutex_unlock(&output_lock
);
340 void status_clear_line ()
342 pthread_cleanup_push(unlock_output_lock
, NULL
);
344 pthread_mutex_lock(&output_lock
);
345 clear_line(last_line_len
);
346 pthread_mutex_unlock(&output_lock
);
348 pthread_cleanup_pop(0);
351 void status_print_statistics (stat_format_t
*stats
,
352 buffer_stats_t
*audio_statistics
,
353 data_source_stats_t
*transport_statistics
,
354 decoder_stats_t
*decoder_statistics
)
356 pthread_cleanup_push(unlock_output_lock
, NULL
);
358 /* Updating statistics is not critical. If another thread is
359 already doing output, we skip it. */
360 if (pthread_mutex_trylock(&output_lock
) == 0) {
362 if (decoder_statistics
!= NULL
) {
363 /* Current playback time */
364 write_time_string(stats
[1].arg
.stringarg
,
365 decoder_statistics
->current_time
);
367 /* Remaining playback time */
368 write_time_string(stats
[2].arg
.stringarg
,
369 decoder_statistics
->total_time
-
370 decoder_statistics
->current_time
);
372 /* Total playback time */
373 write_time_string(stats
[3].arg
.stringarg
,
374 decoder_statistics
->total_time
);
376 /* Instantaneous bitrate */
377 stats
[4].arg
.doublearg
= decoder_statistics
->instant_bitrate
/ 1000.0f
;
379 /* Instantaneous bitrate */
380 stats
[5].arg
.doublearg
= decoder_statistics
->avg_bitrate
/ 1000.0f
;
384 if (transport_statistics
!= NULL
&&
385 transport_statistics
->input_buffer_used
) {
387 /* Input buffer fill % */
388 stats
[6].arg
.doublearg
= transport_statistics
->input_buffer
.fill
;
390 /* Input buffer state */
391 write_buffer_state_string(stats
[7].arg
.stringarg
,
392 &transport_statistics
->input_buffer
);
396 if (audio_statistics
!= NULL
) {
398 /* Output buffer fill % */
399 stats
[8].arg
.doublearg
= audio_statistics
->fill
;
401 /* Output buffer state */
402 write_buffer_state_string(stats
[9].arg
.stringarg
, audio_statistics
);
405 last_line_len
= print_statistics_line(stats
);
407 pthread_mutex_unlock(&output_lock
);
410 pthread_cleanup_pop(0);
414 void status_message (int verbosity
, const char *fmt
, ...)
418 if (verbosity
> max_verbosity
)
421 pthread_cleanup_push(unlock_output_lock
, NULL
);
423 pthread_mutex_lock(&output_lock
);
425 clear_line(last_line_len
);
428 vstatus_print_nolock(fmt
, ap
);
431 pthread_mutex_unlock(&output_lock
);
433 pthread_cleanup_pop(0);
437 void vstatus_message (int verbosity
, const char *fmt
, va_list ap
)
439 if (verbosity
> max_verbosity
)
442 pthread_cleanup_push(unlock_output_lock
, NULL
);
444 pthread_mutex_lock(&output_lock
);
446 clear_line(last_line_len
);
447 vstatus_print_nolock(fmt
, ap
);
449 pthread_mutex_unlock(&output_lock
);
451 pthread_cleanup_pop(0);
455 void status_error (const char *fmt
, ...)
459 pthread_cleanup_push(unlock_output_lock
, NULL
);
461 pthread_mutex_lock(&output_lock
);
463 clear_line(last_line_len
);
464 vstatus_print_nolock (fmt
, ap
);
466 pthread_mutex_unlock(&output_lock
);
468 pthread_cleanup_pop(0);
470 exit_status
= EXIT_FAILURE
;
474 void vstatus_error (const char *fmt
, va_list ap
)
476 pthread_cleanup_push(unlock_output_lock
, NULL
);
478 pthread_mutex_lock(&output_lock
);
479 clear_line(last_line_len
);
480 vstatus_print_nolock (fmt
, ap
);
481 pthread_mutex_unlock(&output_lock
);
483 pthread_cleanup_pop(0);
485 exit_status
= EXIT_FAILURE
;