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 ********************************************************************
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
, "%s", 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
, fcntl(STDERR_FILENO
, F_GETFL
) | O_NONBLOCK
);
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
);
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
, ...)
424 if (verbosity
> max_verbosity
)
427 pthread_cleanup_push(unlock_output_lock
, NULL
);
429 pthread_mutex_lock(&output_lock
);
431 clear_line(last_line_len
);
434 vstatus_print_nolock(fmt
, 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
)
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
, ...)
465 pthread_cleanup_push(unlock_output_lock
, NULL
);
467 pthread_mutex_lock(&output_lock
);
469 clear_line(last_line_len
);
470 vstatus_print_nolock (fmt
, 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
;