Index: include/libroar/vs.h
===================================================================
--- include/libroar/vs.h	(revision 4204)
+++ include/libroar/vs.h	(revision 4206)
@@ -42,4 +42,5 @@
 
 typedef struct roar_vs roar_vs_t;
+typedef signed long int roar_mus_t;
 
 /* return readable string descriping the problem */
@@ -125,5 +126,7 @@
 #define ROAR_VS_BACKEND_MEAN    -3
 
-ssize_t roar_vs_latency(roar_vs_t * vss, int backend, int * error);
+ssize_t roar_vs_position(roar_vs_t * vss, int backend, int * error);
+
+roar_mus_t roar_vs_latency(roar_vs_t * vss, int backend, int * error);
 
 /* set pause flag
Index: libroar/vs.c
===================================================================
--- libroar/vs.c	(revision 4199)
+++ libroar/vs.c	(revision 4206)
@@ -39,4 +39,5 @@
 #define FLAG_STREAM   0x0001
 #define FLAG_NONBLOCK 0x0002
+#define FLAG_BUFFERED 0x0004
 
 #define _initerr()  do { errno = 0; roar_err_clear(); } while(0)
@@ -51,5 +52,11 @@
  struct roar_stream       stream;
  struct roar_vio_calls    vio;
+ struct roar_audio_info   info;
+ size_t                   readc, writec;
+ int                      mixerid;
+ int                      first_primid;
 };
+
+static int _roar_vs_find_first_prim(roar_vs_t * vss);
 
 const char * roar_vs_strerr(int error) {
@@ -93,4 +100,7 @@
  memset(vss, 0, sizeof(roar_vs_t));
 
+ vss->mixerid      = -1;
+ vss->first_primid = -1;
+
  return vss;
 }
@@ -130,4 +140,5 @@
 
 int roar_vs_stream(roar_vs_t * vss, const struct roar_audio_info * info, int dir, int * error) {
+ struct roar_stream_info sinfo;
  int ret;
 
@@ -138,4 +149,7 @@
 
  _initerr();
+
+ if ( info != &(vss->info) )
+  memcpy(&(vss->info), info, sizeof(struct roar_audio_info));
 
  ret = roar_vio_simple_new_stream_obj(&(vss->vio), vss->con, &(vss->stream),
@@ -149,4 +163,9 @@
  }
 
+ if ( roar_stream_get_info(vss->con, &(vss->stream), &sinfo) != -1 ) {
+  vss->mixerid = sinfo.mixer;
+  _roar_vs_find_first_prim(vss);
+ }
+
  vss->flags |= FLAG_STREAM;
 
@@ -156,5 +175,4 @@
 roar_vs_t * roar_vs_new_simple(const char * server, const char * name, int rate, int channels, int codec, int bits, int dir, int * error) {
  roar_vs_t * vss = roar_vs_new(server, name, error);
- struct roar_audio_info info;
  int ret;
 
@@ -162,12 +180,12 @@
   return NULL;
 
- memset(&info, 0, sizeof(info));
-
- info.rate     = rate;
- info.channels = channels;
- info.codec    = codec;
- info.bits     = bits;
-
- ret = roar_vs_stream(vss, &info, dir, error);
+ memset(&(vss->info), 0, sizeof(vss->info));
+
+ vss->info.rate     = rate;
+ vss->info.channels = channels;
+ vss->info.codec    = codec;
+ vss->info.bits     = bits;
+
+ ret = roar_vs_stream(vss, &(vss->info), dir, error);
 
  if (ret == -1) {
@@ -225,4 +243,6 @@
 
   _seterrre();
+ } else {
+  vss->writec += ret;
  }
 
@@ -244,4 +264,6 @@
  if ( ret == -1 ) {
   _seterrre();
+ } else {
+  vss->readc += ret;
  }
 
@@ -316,7 +338,134 @@
 }
 
-ssize_t roar_vs_latency(roar_vs_t * vss, int backend, int * error) {
+static int _roar_vs_find_first_prim(roar_vs_t * vss) {
+ struct roar_stream stream;
+ struct roar_stream_info info;
+ int id[ROAR_STREAMS_MAX];
+ int num;
+ int i;
+
+ if ( vss->first_primid != -1 )
+  return vss->first_primid;
+
+ if ( vss->mixerid == -1 )
+  return -1;
+
+ if ( (num = roar_list_streams(vss->con, id, ROAR_STREAMS_MAX)) == -1 ) {
+  return -1;
+ }
+
+ for (i = 0; i < num; i++) {
+  if ( roar_get_stream(vss->con, &stream, id[i]) == -1 )
+   continue;
+
+  if ( stream.dir != ROAR_DIR_OUTPUT )
+   continue;
+
+  if ( roar_stream_get_info(vss->con, &stream, &info) == -1 )
+   continue;
+
+  if ( info.mixer == vss->mixerid ) {
+   vss->first_primid = id[i];
+   return id[i];
+  }
+ }
+
+ return -1;
+}
+
+ssize_t roar_vs_position(roar_vs_t * vss, int backend, int * error) {
+ struct roar_stream stream;
+ struct roar_stream      out_stream;
+ struct roar_stream_info out_info;
+ size_t offset;
+
+ if ( !(vss->flags & FLAG_STREAM) ) {
+  _seterr(ROAR_ERROR_INVAL);
+  return -1;
+ }
+
+ _initerr();
+
+ if ( roar_get_stream(vss->con, &stream, roar_stream_get_id(&(vss->stream))) == -1 ) {
+  _seterrre();
+  return -1;
+ }
+
+ switch (backend) {
+  case ROAR_VS_BACKEND_NONE:
+    return stream.pos;
+   break;
+  case ROAR_VS_BACKEND_FIRST:
+   // _roar_vs_find_first_prim(vss);
+    if ( vss->first_primid == -1 ) {
+     _seterr(ROAR_ERROR_UNKNOWN);
+     return -1;
+    }
+
+    roar_stream_new_by_id(&out_stream, vss->first_primid);
+
+    if ( roar_stream_get_info(vss->con, &out_stream, &out_info) == -1 ) {
+     _seterrre();
+     return -1;
+    }
+
+    offset  = out_info.delay * vss->info.rate;
+    offset /= 1000000;
+
+    return stream.pos + offset;
+   break;
+  default:
+    _seterr(ROAR_ERROR_NOTSUP);
+    return -1;
+   break;
+ }
+
  _seterr(ROAR_ERROR_NOSYS);
  return -1;
+}
+
+roar_mus_t roar_vs_latency(roar_vs_t * vss, int backend, int * error) {
+ ssize_t pos  = roar_vs_position(vss, backend, error);
+ ssize_t bps;  // byte per sample
+ size_t  lioc; // local IO (byte) counter
+ size_t  lpos; // local possition
+ roar_mus_t  lag;
+
+ if (pos == -1)
+  return -1;
+
+ if ( !(vss->flags & FLAG_STREAM) ) {
+  _seterr(ROAR_ERROR_INVAL);
+  return -1;
+ }
+
+ if ( vss->writec == 0 ) {
+  lioc = vss->readc;
+ } else {
+  lioc = vss->writec;
+ }
+
+ _initerr();
+
+ bps = roar_info2samplesize(&(vss->info));
+
+ if ( bps == -1 ) {
+  _seterrre();
+  return -1;
+ }
+
+ lpos = lioc / bps;
+
+ lag = (roar_mus_t)lpos - (roar_mus_t)pos;
+
+ // we now have the lag in frames
+ // return value are ms
+ // so we need to multiply with 1s/ms and
+ // multiply by 1/rate
+
+ lag *= 1000000; // 1s/ms
+ lag /= vss->info.rate;
+
+ return lag;
 }
 
