source: roaraudio/roarclients/roarvorbis.c @ 5908:66940b2023ee

Last change on this file since 5908:66940b2023ee was 5823:f9f70dbaa376, checked in by phi, 11 years ago

updated copyright

File size: 10.2 KB
RevLine 
[111]1//roarvorbis.c:
2
[669]3/*
[5823]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2013
[669]5 *
6 *  This file is part of roarclients a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[669]23 *
24 */
25
[111]26#include <roaraudio.h>
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <math.h>
[478]31#ifdef ROAR_HAVE_LIBVORBISFILE
[111]32#include <vorbis/codec.h>
33#include <vorbis/vorbisfile.h>
[478]34#endif
[111]35
36#ifdef _WIN32
37#include <io.h>
38#include <fcntl.h>
39#endif
40
41#define BUFSIZE 1024
42
43void usage (void) {
44 printf("roarvorbis [OPTIONS]... FILE\n");
45
46 printf("\nOptions:\n\n");
47
48 printf("  --server SERVER    - Set server hostname\n"
49        "  --help             - Show this help\n"
[3043]50        "  --vclt-out FILE    - Writes VCLT file\n"
[111]51       );
52
53}
54
[124]55
[478]56#ifdef ROAR_HAVE_LIBVORBISFILE
[4656]57int _g_cf_vorbis_vfvio_return_err (void) {
58 return -1;
59}
60
61size_t cf_vorbis_vfvio_read (void *ptr, size_t size, size_t nmemb, void *datasource) {
62 ssize_t r;
[124]63
[4656]64 r = roar_vio_read(datasource, ptr, size*nmemb);
65
[5651]66 ROAR_DBG("cf_vorbis_vfvio_read(ptr=%p, size=%lu, nmemb=%lu, datasource=%p): r=%i", ptr, (unsigned long int)size, (unsigned long int)nmemb, datasource, r);
[4656]67
68 if ( r == -1 )
69  return 0;
[124]70
[4656]71 if ( r > 0 )
72  errno = 0;
73
74 r /= size;
75
[5651]76 ROAR_DBG("cf_vorbis_vfvio_read(ptr=%p, size=%lu, nmemb=%lu, datasource=%p) = %i", ptr, (unsigned long int)size, (unsigned long int)nmemb, datasource, r);
[4656]77 return r;
[124]78}
79
[4754]80int cf_vorbis_vfvio_seek  (void *datasource, ogg_int64_t offset, int whence) {
81 return roar_vio_lseek(datasource, offset, whence);
82}
83
84long cf_vorbis_vfvio_tell (void *datasource) {
85 return roar_vio_lseek(datasource, 0, SEEK_CUR);
86}
[4656]87
88ov_callbacks _g_cf_vorbis_vfvio = {
89  .read_func  = cf_vorbis_vfvio_read,
[4754]90  .seek_func  = cf_vorbis_vfvio_seek,
[4656]91  .close_func = (int    (*)(void *                        )) _g_cf_vorbis_vfvio_return_err,
[4754]92  .tell_func  = cf_vorbis_vfvio_tell
[4656]93};
94
95
[4659]96int update_stream (struct roar_connection *  con,
97                   roar_vs_t              ** vss,
98                   OggVorbis_File         *  vf,
[5534]99                   const char             *  file,
[4659]100                   struct roar_audio_info *  info,
101                   struct roar_vio_calls  *  vclt) {
102 struct roar_stream     * s;
[121]103 vorbis_info *vi = ov_info(vf, -1);
[111]104 int    bits     = 16;
[4659]105 int    codec    = ROAR_CODEC_PCM_S_LE;
[121]106 char **ptr = ov_comment(vf, -1)->user_comments;
[718]107 char key[ROAR_META_MAX_NAMELEN], value[LIBROAR_BUFFER_MSGDATA] = {0};
[121]108 int j, h = 0;
109 struct roar_meta   meta;
[3843]110 static int need_new_stream = 1;
111 int need_close = 0;
[715]112 int meta_ok;
[121]113
114 fprintf(stderr, "\n");
115
[3045]116 if ( vclt != NULL ) {
[5651]117  roar_vio_printf(vclt, "AUDIOINFO=rate:%liHz, channels:%li\n", (long int)vi->rate, (long int)vi->channels);
[3045]118 }
119
[3843]120 if ( !need_new_stream ) {
121  if ( info->rate != (uint16_t)vi->rate || info->channels != (uint16_t)vi->channels ) {
122   need_close      = 1;
123   need_new_stream = 1;
124  }
[122]125 }
126
127 if ( need_new_stream ) {
[4659]128  if ( need_close ) {
129   roar_vs_sync(*vss, ROAR_VS_WAIT, NULL);
130   roar_vs_close(*vss, ROAR_VS_FALSE, NULL);
131  }
[121]132
[122]133  fprintf(stderr, "Audio: %i channel, %liHz\n\n", vi->channels, vi->rate);
134
135  info->rate     = vi->rate;
136  info->channels = vi->channels;
[4659]137  info->bits     = bits;
138  info->codec    = codec;
[121]139
[4659]140  *vss = roar_vs_new_from_con(con, NULL);
141  if ( *vss == NULL ) {
[122]142   roar_disconnect(con);
143   return -1;
144  }
[4659]145
146  if ( roar_vs_stream(*vss, info, ROAR_DIR_PLAY, NULL) == -1 ) {
147   roar_vs_close(*vss, ROAR_VS_TRUE, NULL);
148   roar_disconnect(con);
149   return -1;
150  }
151
[3843]152  need_new_stream = 0;
[121]153 }
154
[4659]155 s = roar_vs_stream_obj(*vss, NULL);
[121]156
157 meta.value = value;
158 meta.key[0] = 0;
[132]159 meta.type = ROAR_META_TYPE_NONE;
[121]160
161 roar_stream_meta_set(con, s, ROAR_META_MODE_CLEAR, &meta);
162
[124]163 if ( strncmp(file, "http:", 5) == 0 )
164  meta.type = ROAR_META_TYPE_FILEURL;
165 else
166  meta.type = ROAR_META_TYPE_FILENAME;
167
[715]168
[719]169 strncpy(value, file, LIBROAR_BUFFER_MSGDATA-1);
170 value[LIBROAR_BUFFER_MSGDATA-1] = 0;
[121]171 roar_stream_meta_set(con, s, ROAR_META_MODE_SET, &meta);
172
173 while(*ptr){
[715]174  meta_ok = 1;
175
176   for (j = 0; (*ptr)[j] != 0 && (*ptr)[j] != '='; j++) {
177    if ( j == ROAR_META_MAX_NAMELEN ) {
178     ROAR_ERR("update_stream(*): invalid meta data: meta data key too long");
179     meta_ok = 0;
180     j = 0;
181     break;
182    }
[121]183    key[j] = (*ptr)[j];
[715]184   }
185   key[j] = 0;
[121]186
[715]187   if ( meta_ok ) {
188    for (j++, h = 0; (*ptr)[j] != 0 && (*ptr)[j] != '='; j++) {
[718]189     if ( h == LIBROAR_BUFFER_MSGDATA ) {
[715]190      ROAR_ERR("update_stream(*): invalid meta data: meta data value for key '%s' too long", key);
191      meta_ok = 0;
192      h = 0;
193      break;
194     }
195     value[h++] = (*ptr)[j];
196    }
[121]197    value[h]   = 0;
[715]198   }
[121]199
[715]200   if ( meta_ok ) {
201    fprintf(stderr, "Meta %-16s: %s\n", key, value);
[121]202
[3043]203    if ( vclt != NULL ) {
204     roar_vio_printf(vclt, "%s=%s\n", key, value);
205    }
206
[715]207    meta.type = roar_meta_inttype(key);
208    if ( meta.type != -1 )
209     roar_stream_meta_set(con, s, ROAR_META_MODE_SET, &meta);
210   }
211
212   ptr++;
[121]213 }
214
[4659]215 fprintf(stderr, "\n");
216
[1238]217 *value      = 0;
218 meta.key[0] = 0;
219 meta.type   = ROAR_META_TYPE_NONE;
220 roar_stream_meta_set(con, s, ROAR_META_MODE_FINALIZE, &meta);
221
[3043]222 if ( vclt != NULL ) {
223  roar_vio_printf(vclt, "==\n");
224 }
225
[121]226 return 0;
227}
228
[4754]229
230const char * time2str(double t, char * buf, size_t len) {
231 int h, m;
232
233 if ( t < 0 ) {
234//  strncpy(buf, "unknown", len);
235//  return buf;
236  *buf++ = '-';
237  t *= -1;
238 }
239
240 h  = t / 3600;
241 t -= h * 3600;
242 m  = t / 60;
243 t -= m * 60;
244
245 snprintf(buf, len, "%.2i:%.2i:%.2i", h, m, (int)t);
246
247 return buf;
248}
249
250void print_time (OggVorbis_File * vf, roar_vs_t * vss, double time_total, struct roar_audio_info * info) {
251 ssize_t pos;
252 double time_cur;
253 long bitrate_cur = ov_bitrate_instant(vf);
254 float bitrate = bitrate_cur / 1000.0;
255 char time_buf[3][10];
256
257 pos = roar_vs_position(vss, ROAR_VS_BACKEND_DEFAULT, NULL);
258
259 if ( pos == -1 ) {
260  time_cur = ov_time_tell(vf);
261 } else {
262  time_cur = (double)pos/(double)(info->channels*info->rate);
263 }
264
265 time2str(time_cur, time_buf[0], sizeof(time_buf[0]));
[4844]266
267 if ( time_total > 0 ) {
268  time2str(time_total-time_cur, time_buf[1], sizeof(time_buf[1]));
269  time2str(time_total, time_buf[2], sizeof(time_buf[2]));
[4754]270
[4844]271  //Time: 00:02.53 [03:26.20] of 03:28.73  (122.7 kbps)  Output Buffer  43.8%
272  fprintf(stderr, "\rTime: %s [%s] of %s  (%.1f kbps)            ", time_buf[0], time_buf[1], time_buf[2], bitrate);
273 } else {
274  fprintf(stderr, "\rTime: %s  (%.1f kbps)                       ", time_buf[0], bitrate);
275 }
276
[4754]277 fflush(stderr);
278}
279
[478]280#endif
281
[121]282int main (int argc, char * argv[]) {
[478]283#ifndef ROAR_HAVE_LIBVORBISFILE
[3787]284 (void)argc, (void)argv;
[479]285 fprintf(stderr, "Error: no Vorbis support!\n");
[478]286 return 1;
287#else
[4656]288 struct roar_vio_calls vclt, in;
[3787]289 struct roar_vio_defaults def;
[5534]290 const char * file     = NULL;
291 const char * vcltfile = NULL;
292 const char * k;
[111]293 int    i;
294 struct roar_connection con;
[4659]295 roar_vs_t * vss = NULL;
[111]296 OggVorbis_File vf;
297 int eof=0;
[132]298 int current_section = -1;
[120]299 int last_section = -1;
[122]300 struct roar_audio_info info;
[111]301 char pcmout[4096];
[4754]302 double time_total;
303 ssize_t bits_per_sec = -1;
304 ssize_t bits_written = -1;
[111]305
306
307 for (i = 1; i < argc; i++) {
308  k = argv[i];
309
310  if ( strcmp(k, "--server") == 0 ) {
[5534]311   roar_libroar_set_server(argv[++i]);
[3043]312  } else if ( strcmp(k, "--vclt-out") == 0 ) {
313   vcltfile = argv[++i];
[111]314  } else if ( strcmp(k, "--help") == 0 ) {
315   usage();
316   return 0;
317  } else if ( file == NULL ) {
318   file = k;
319  } else {
320   fprintf(stderr, "Error: unknown argument: %s\n", k);
321   usage();
322   return 1;
323  }
324 }
325
[1510]326 if ( file == NULL ) {
327  ROAR_ERR("No filename given.");
328  return 1;
329 }
330
[4656]331 if ( roar_vio_dstr_init_defaults(&def, ROAR_VIO_DEF_TYPE_NONE, O_RDONLY, 0644) == -1 )
332  return 1;
333
334 if ( roar_vio_open_dstr(&in, file, &def, 1) == -1 ) {
335  fprintf(stderr, "Error: can not open file: %s: %s\n", file, strerror(errno));
[1406]336  return 1;
[111]337 }
338
[5139]339 if ( roar_simple_connect(&con, NULL, "roarvorbis") == -1 ) {
[4656]340  ROAR_DBG("roar_simple_play(*): roar_simple_connect() faild!");
341  roar_vio_close(&in);
[1406]342  return 1;
[111]343 }
344
[4656]345 if ( ov_open_callbacks((void*)&in, &vf, NULL, 0, _g_cf_vorbis_vfvio) < 0 ) {
346// if( ov_open(in, &vf, NULL, 0) < 0 ) {
[111]347  fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n");
348  roar_disconnect(&con);
[4656]349  roar_vio_close(&in);
[1406]350  return 1;
[111]351 }
352
[4754]353 time_total = ov_time_total(&vf, -1);
354
[3043]355 if ( vcltfile != NULL ) {
356  if ( roar_vio_dstr_init_defaults(&def, ROAR_VIO_DEF_TYPE_NONE, O_WRONLY|O_CREAT|O_APPEND, 0644) == -1 )
357   return 1;
358  if ( roar_vio_open_dstr(&vclt, vcltfile, &def, 1) == -1 ) {
[5139]359   fprintf(stderr, "Error: can not open file: %s: %s\n", vcltfile, strerror(errno));
[4656]360   roar_disconnect(&con);
361   roar_vio_close(&in);
[3043]362   return 1;
363  }
364 }
365
[121]366// if ( update_stream(&con, &s, &out, &vf, file) == -1 )
[1406]367//  return 1;
[111]368
[117]369 while (!eof) {
370  long ret = ov_read(&vf, pcmout, sizeof(pcmout), 0, 2, 1, &current_section);
[120]371
[121]372  if ( last_section != current_section )
[4659]373   if ( update_stream(&con, &vss, &vf, file, &info, vcltfile == NULL ? NULL : &vclt) == -1 ) {
[4656]374    roar_vio_close(&in);
375    if ( vcltfile != NULL )
376     roar_vio_close(&vclt);
[715]377    return 1;
[4014]378   }
[4754]379   bits_per_sec = roar_info2bitspersec(&info);
[121]380
[120]381  last_section = current_section;
382
[111]383  if (ret == 0) {
384   /* EOF */
[3843]385   eof = 1;
[111]386  } else if (ret < 0) {
387   /* error in the stream.  Not a problem, just reporting it in
388      case we (the app) cares.  In this case, we don't. */
389  } else {
[5249]390   if ( roar_vs_write(vss, pcmout, ret, NULL) != (ssize_t)ret ) {
391    fprintf(stderr, "\nError: Can not write to server.\n");
392    eof = 1;
393    continue;
394   }
[4754]395   bits_written += ret * 8;
396   if ( bits_written > bits_per_sec ) {
397    bits_written = 0;
398    print_time(&vf, vss, time_total, &info);
399   }
[111]400  }
401 }
402
[4754]403 fprintf(stderr, "\n"); // end the lion of print_time().
404
[3843]405 ov_clear(&vf);
[111]406
407// fclose(in);
[4659]408 roar_vs_close(vss, ROAR_VS_FALSE, NULL);
[120]409 roar_disconnect(&con);
[111]410
[4656]411 if ( vcltfile != NULL )
[3043]412  roar_vio_close(&vclt);
413
[4656]414 roar_vio_close(&in);
[4014]415
[111]416 return 0;
[478]417#endif
[111]418}
419
420//ll
Note: See TracBrowser for help on using the repository browser.