[polypaudio-commits] r686 - in /trunk/src/polyp: def.h internal.h stream.c

svnmailer-noreply at 0pointer.de svnmailer-noreply at 0pointer.de
Wed Apr 12 10:17:25 PDT 2006


Author: lennart
Date: Wed Apr 12 19:17:23 2006
New Revision: 686

URL: http://0pointer.de/cgi-bin/viewcvs.cgi?rev=686&root=polypaudio&view=rev
Log:
* rename "latency correction" to "write index correction"
* add read index invalidation code
* rename "ipol_event" stuff to "auto_timing_update"
* remove buffer_usec field from pa_timing_info, since it can be easily calculated from write_index and read_index anyway
* add read_index_corrupt field to "pa_timing_info", similar to the already existing write_index_corrupt field
* restart automatic timing update event every time a query is issued, not just when the last event elapsed
* proper invalidation code for pa_stream_flush()
* do tarsnport/sink/source latency correction for playback time only when device is not corked

Modified:
    trunk/src/polyp/def.h
    trunk/src/polyp/internal.h
    trunk/src/polyp/stream.c

Modified: trunk/src/polyp/def.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/polyp/def.h?rev=686&root=polypaudio&r1=685&r2=686&view=diff
==============================================================================
--- trunk/src/polyp/def.h (original)
+++ trunk/src/polyp/def.h Wed Apr 12 19:17:23 2006
@@ -204,13 +204,14 @@
  * pa_stream_update_timing_info() and pa_stream_get_timing_info(). The
  * total output latency a sample that is written with
  * pa_stream_write() takes to be played may be estimated by
- * sink_usec+buffer_usec+transport_usec. The output buffer to which
- * buffer_usec relates may be manipulated freely (with
+ * sink_usec+buffer_usec+transport_usec. (where buffer_usec is defined
+ * as pa_bytes_to_usec(write_index-read_index)) The output buffer 
+ * which buffer_usec relates to may be manipulated freely (with
  * pa_stream_write()'s seek argument, pa_stream_flush() and friends),
  * the buffers sink_usec and source_usec relate to are first-in
- * first-out (FIFO) buffers which cannot be flushed or manipulated in any
- * way. The total input latency a sample that is recorded takes to be
- * delivered to the application is:
+ * first-out (FIFO) buffers which cannot be flushed or manipulated in
+ * any way. The total input latency a sample that is recorded takes to
+ * be delivered to the application is:
  * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of
  * sign issues!) When connected to a monitor source sink_usec contains
  * the latency of the owning sink. The two latency estimations
@@ -226,7 +227,6 @@
                                * limited und unreliable itself. \since
                                * 0.5 */
 
-    pa_usec_t buffer_usec;    /**< Time in usecs the current buffer takes to play. For both playback and record streams. */
     pa_usec_t sink_usec;      /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */
     pa_usec_t source_usec;    /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/
     pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */
@@ -240,14 +240,21 @@
                                * info was current . Only write
                                * commands with SEEK_RELATIVE_ON_READ
                                * and SEEK_RELATIVE_END can corrupt
-                               * write_index. */
+                               * write_index. \since 0.8 */
     int64_t write_index;      /**< Current write index into the
                                * playback buffer in bytes. Think twice before
                                * using this for seeking purposes: it
                                * might be out of date a the time you
                                * want to use it. Consider using
                                * PA_SEEK_RELATIVE instead. \since
-                               * 0.8 */ 
+                               * 0.8 */
+
+    int read_index_corrupt;   /**< Non-zero if read_index is not
+                               * up-to-date because a local pause or
+                               * flush request that corrupted it has
+                               * been issued in the time since this
+                               * latency info was current. \since 0.8  */
+    
     int64_t read_index;       /**< Current read index into the
                                * playback buffer in bytes. Think twice before
                                * using this for seeking purposes: it

Modified: trunk/src/polyp/internal.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/polyp/internal.h?rev=686&root=polypaudio&r1=685&r2=686&view=diff
==============================================================================
--- trunk/src/polyp/internal.h (original)
+++ trunk/src/polyp/internal.h Wed Apr 12 19:17:23 2006
@@ -83,14 +83,14 @@
     pa_client_conf *conf;
 };
 
-#define PA_MAX_LATENCY_CORRECTIONS 10
-
-typedef struct pa_latency_correction {
+#define PA_MAX_WRITE_INDEX_CORRECTIONS 10
+
+typedef struct pa_index_correction {
     uint32_t tag;
     int valid;
     int64_t value;
     int absolute, corrupt;
-} pa_latency_correction;
+} pa_index_correction;
 
 struct pa_stream {
     int ref;
@@ -124,13 +124,18 @@
     /* Use to make sure that time advances monotonically */
     pa_usec_t previous_time;
     
-    /* Latency correction stuff */
-    pa_latency_correction latency_corrections[PA_MAX_LATENCY_CORRECTIONS];
-    int idx_latency_correction;
+    /* time updates with tags older than these are invalid */
+    uint32_t write_index_not_before;
+    uint32_t read_index_not_before;
+
+    /* Data about individual timing update correctoins */
+    pa_index_correction write_index_corrections[PA_MAX_WRITE_INDEX_CORRECTIONS];
+    int current_write_index_correction;
 
     /* Latency interpolation stuff */
-    pa_time_event *ipol_event;
-    int ipol_requested;
+    pa_time_event *auto_timing_update_event;
+    int auto_timing_update_requested;
+    
     pa_usec_t ipol_usec;
     int ipol_usec_valid;
     struct timeval ipol_timestamp;

Modified: trunk/src/polyp/stream.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/polyp/stream.c?rev=686&root=polypaudio&r1=685&r2=686&view=diff
==============================================================================
--- trunk/src/polyp/stream.c (original)
+++ trunk/src/polyp/stream.c Wed Apr 12 19:17:23 2006
@@ -90,19 +90,22 @@
 
     s->previous_time = 0;
     s->timing_info_valid = 0;
-
+    s->read_index_not_before = 0;
+    s->write_index_not_before = 0;
+
+    for (i = 0; i < PA_MAX_WRITE_INDEX_CORRECTIONS; i++)
+        s->write_index_corrections[i].valid = 0;
+    s->current_write_index_correction = 0;
+    
     s->corked = 0;
 
     s->ipol_usec_valid = 0;
     s->ipol_timestamp.tv_sec = 0;
     s->ipol_timestamp.tv_usec = 0;
-    s->ipol_event = NULL;
-    s->ipol_requested = 0;
-
-    for (i = 0; i < PA_MAX_LATENCY_CORRECTIONS; i++)
-        s->latency_corrections[i].valid = 0;
-    s->idx_latency_correction = 0;
-    
+    
+    s->auto_timing_update_event = NULL;
+    s->auto_timing_update_requested = 0;
+
     PA_LLIST_PREPEND(pa_stream, c->streams, s);
 
     /* The context and stream will point at each other. We cannot ref count
@@ -119,9 +122,9 @@
 
     pa_context_unref(s->context);
 
-    if (s->ipol_event) {
+    if (s->auto_timing_update_event) {
         assert(s->mainloop);
-        s->mainloop->time_free(s->ipol_event);
+        s->mainloop->time_free(s->auto_timing_update_event);
     }
 
     if (s->peek_memchunk.memblock)
@@ -296,34 +299,77 @@
         }
     }
 
-finish:
+ finish:
     pa_context_unref(c);
 }
 
-static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
+static void request_auto_timing_update(pa_stream *s, int force) {
     struct timeval next;
-    pa_stream *s = userdata;
-
-    pa_stream_ref(s);
-
-/*     pa_log("requesting new ipol data"); */
-    
-    if (s->state == PA_STREAM_READY && !s->ipol_requested) {
+    assert(s);
+
+    if (!(s->flags & PA_STREAM_AUTO_TIMING_UPDATE))
+        return;
+    
+    if (s->state == PA_STREAM_READY &&
+        (force || !s->auto_timing_update_requested)) {
         pa_operation *o;
         
+/*         pa_log("automatically requesting new timing data");   */
+
         if ((o = pa_stream_update_timing_info(s, NULL, NULL))) {
             pa_operation_unref(o);
-            s->ipol_requested = 1;
+            s->auto_timing_update_requested = 1;
         }
     }
-    
+
     pa_gettimeofday(&next);
     pa_timeval_add(&next, LATENCY_IPOL_INTERVAL_USEC);
-    m->time_restart(e, &next);
-    
+    s->mainloop->time_restart(s->auto_timing_update_event, &next);
+}
+
+static void invalidate_indexes(pa_stream *s, int r, int w) {
+    assert(s);
+
+    pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag);
+    
+    if (s->state != PA_STREAM_READY)
+        return;
+
+    if (w) {
+        s->write_index_not_before = s->context->ctag;
+        
+        if (s->timing_info_valid)
+            s->timing_info.write_index_corrupt = 1;
+        
+        pa_log("write_index invalidated");
+        
+    }
+    
+    if (r) {
+        s->read_index_not_before = s->context->ctag;
+        
+        if (s->timing_info_valid)
+            s->timing_info.read_index_corrupt = 1;
+        
+        pa_log("read_index invalidated");
+    }
+    
+    if ((s->direction == PA_STREAM_PLAYBACK && r) ||
+        (s->direction == PA_STREAM_RECORD && w))
+        s->ipol_usec_valid = 0;
+    
+    request_auto_timing_update(s, 1);
+}
+
+static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
+    pa_stream *s = userdata;
+
+    pa_log("time event");   
+
+    pa_stream_ref(s);
+    request_auto_timing_update(s, 0);
     pa_stream_unref(s);
 }
-
 
 void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
     pa_stream *s = userdata;
@@ -371,6 +417,8 @@
     /* We add an extra ref as long as we're connected (i.e. in the dynarray) */
     pa_stream_ref(s);
 
+    pa_stream_set_state(s, PA_STREAM_READY);
+    
     if (s->direction != PA_STREAM_UPLOAD &&
         s->flags & PA_STREAM_AUTO_TIMING_UPDATE) {
         struct timeval tv;
@@ -378,12 +426,12 @@
         pa_gettimeofday(&tv);
         tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */
 
-        assert(!s->ipol_event);
-        s->ipol_event = s->mainloop->time_new(s->mainloop, &tv, &ipol_callback, s);
-    }
-
-    pa_stream_set_state(s, PA_STREAM_READY);
-    
+        assert(!s->auto_timing_update_event);
+        s->auto_timing_update_event = s->mainloop->time_new(s->mainloop, &tv, &auto_timing_update_callback, s);
+
+        request_auto_timing_update(s, 1);
+    }
+
     if (s->requested_bytes > 0 && s->ref > 1 && s->write_callback)
         s->write_callback(s, s->requested_bytes, s->write_userdata);
 
@@ -548,18 +596,19 @@
         s->requested_bytes = 0;
 
     if (s->direction == PA_STREAM_PLAYBACK) {
+        
         /* Update latency request correction */
-        if (s->latency_corrections[s->idx_latency_correction].valid) {
+        if (s->write_index_corrections[s->current_write_index_correction].valid) {
             
             if (seek == PA_SEEK_ABSOLUTE) {
-                s->latency_corrections[s->idx_latency_correction].corrupt = 0;
-                s->latency_corrections[s->idx_latency_correction].absolute = 1;
-                s->latency_corrections[s->idx_latency_correction].value = offset + length;
+                s->write_index_corrections[s->current_write_index_correction].corrupt = 0;
+                s->write_index_corrections[s->current_write_index_correction].absolute = 1;
+                s->write_index_corrections[s->current_write_index_correction].value = offset + length;
             } else if (seek == PA_SEEK_RELATIVE) {
-                if (!s->latency_corrections[s->idx_latency_correction].corrupt)
-                    s->latency_corrections[s->idx_latency_correction].value += offset + length;
+                if (!s->write_index_corrections[s->current_write_index_correction].corrupt)
+                    s->write_index_corrections[s->current_write_index_correction].value += offset + length;
             } else
-                s->latency_corrections[s->idx_latency_correction].corrupt = 1;
+                s->write_index_corrections[s->current_write_index_correction].corrupt = 1;
         }
         
         /* Update the write index in the already available latency data */
@@ -574,6 +623,9 @@
             } else
                 s->timing_info.write_index_corrupt = 1;
         }
+
+        if (!s->timing_info_valid || s->timing_info.write_index_corrupt)
+            request_auto_timing_update(s, 1);
     }
     
     return 0;
@@ -672,15 +724,20 @@
     assert(o->context);
 
     i = &o->stream->timing_info;
+
+    pa_log("pre corrupt w:%u r:%u\n", !o->stream->timing_info_valid || i->write_index_corrupt,!o->stream->timing_info_valid || i->read_index_corrupt);
+    
     o->stream->timing_info_valid = 0;
     i->write_index_corrupt = 0;
+    i->read_index_corrupt = 0;
+
+    pa_log("timing update %u\n", tag);
 
     if (command != PA_COMMAND_REPLY) {
         if (pa_context_handle_error(o->context, command, t) < 0)
             goto finish;
 
-    } else if (pa_tagstruct_get_usec(t, &i->buffer_usec) < 0 ||
-               pa_tagstruct_get_usec(t, &i->sink_usec) < 0 ||
+    } else if (pa_tagstruct_get_usec(t, &i->sink_usec) < 0 ||
                pa_tagstruct_get_usec(t, &i->source_usec) < 0 ||
                pa_tagstruct_get_boolean(t, &i->playing) < 0 ||
                pa_tagstruct_get_timeval(t, &local) < 0 ||
@@ -692,8 +749,11 @@
         goto finish;
         
     } else {
+        o->stream->timing_info_valid = 1;
+
         pa_gettimeofday(&now);
         
+        /* Calculcate timestamps */
         if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) {
             /* local and remote seem to have synchronized clocks */
             
@@ -712,6 +772,13 @@
             pa_timeval_add(&i->timestamp, i->transport_usec);
         }
 
+        /* Invalidate read and write indexes if necessary */
+        if (tag < o->stream->read_index_not_before)
+            i->read_index_corrupt = 1;
+
+        if (tag < o->stream->write_index_not_before)
+            i->write_index_corrupt = 1;
+
         if (o->stream->direction == PA_STREAM_PLAYBACK) {
             /* Write index correction */
 
@@ -720,53 +787,54 @@
 
             /* Go through the saved correction values and add up the total correction.*/
             
-            for (n = 0, j = o->stream->idx_latency_correction;
-                 n < PA_MAX_LATENCY_CORRECTIONS;
-                 n++, j = (j + 1) % PA_MAX_LATENCY_CORRECTIONS) {
+            for (n = 0, j = o->stream->current_write_index_correction+1;
+                 n < PA_MAX_WRITE_INDEX_CORRECTIONS;
+                 n++, j = (j + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS) {
 
                 /* Step over invalid data or out-of-date data */
-                if (!o->stream->latency_corrections[j].valid ||
-                    o->stream->latency_corrections[j].tag < ctag)
+                if (!o->stream->write_index_corrections[j].valid ||
+                    o->stream->write_index_corrections[j].tag < ctag)
                     continue;
 
                 /* Make sure that everything is in order */
-                ctag = o->stream->latency_corrections[j].tag+1;
+                ctag = o->stream->write_index_corrections[j].tag+1;
 
                 /* Now fix the write index */
-                if (o->stream->latency_corrections[j].corrupt) {
+                if (o->stream->write_index_corrections[j].corrupt) {
                     /* A corrupting seek was made */
                     i->write_index = 0;
                     i->write_index_corrupt = 1;
-                } else if (o->stream->latency_corrections[j].absolute) {
+                } else if (o->stream->write_index_corrections[j].absolute) {
                     /* An absolute seek was made */
-                    i->write_index = o->stream->latency_corrections[j].value;
+                    i->write_index = o->stream->write_index_corrections[j].value;
                     i->write_index_corrupt = 0;
                 } else if (!i->write_index_corrupt) {
                     /* A relative seek was made */
-                    i->write_index += o->stream->latency_corrections[j].value;
+                    i->write_index += o->stream->write_index_corrections[j].value;
                 }
             }
         }
-        
-        o->stream->timing_info_valid = 1;
-        
+
         o->stream->ipol_timestamp = now;
         o->stream->ipol_usec_valid = 0;
     }
 
+    o->stream->auto_timing_update_requested = 0;
+    pa_log("post corrupt w:%u r:%u\n", i->write_index_corrupt || !o->stream->timing_info_valid, i->read_index_corrupt || !o->stream->timing_info_valid);
+    
     /* Clear old correction entries */
     if (o->stream->direction == PA_STREAM_PLAYBACK) {
         int n;
         
-        for (n = 0; n < PA_MAX_LATENCY_CORRECTIONS; n++) {
-            if (!o->stream->latency_corrections[n].valid)
+        for (n = 0; n < PA_MAX_WRITE_INDEX_CORRECTIONS; n++) {
+            if (!o->stream->write_index_corrections[n].valid)
                 continue;
             
-            if (o->stream->latency_corrections[n].tag <= tag)
-                o->stream->latency_corrections[n].valid = 0;
+            if (o->stream->write_index_corrections[n].tag <= tag)
+                o->stream->write_index_corrections[n].valid = 0;
         }
     }
-
+    
     if (o->callback) {
         pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback;
         cb(o->stream, o->stream->timing_info_valid, o->userdata);
@@ -790,16 +858,15 @@
 
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
-
+    
     if (s->direction == PA_STREAM_PLAYBACK) {
         /* Find a place to store the write_index correction data for this entry */
-        cidx = (s->idx_latency_correction + 1) % PA_MAX_LATENCY_CORRECTIONS;
+        cidx = (s->current_write_index_correction + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS;
         
         /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */
-        PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->latency_corrections[cidx].valid, PA_ERR_INTERNAL);
-    }
-    
-    o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
+        PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->write_index_corrections[cidx].valid, PA_ERR_INTERNAL);
+    }
+      o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
     
     t = pa_tagstruct_command(
             s->context,
@@ -813,13 +880,15 @@
 
     if (s->direction == PA_STREAM_PLAYBACK) {
         /* Fill in initial correction data */
-        o->stream->idx_latency_correction = cidx;
-        o->stream->latency_corrections[cidx].valid = 1;
-        o->stream->latency_corrections[cidx].tag = tag;
-        o->stream->latency_corrections[cidx].absolute = 0;
-        o->stream->latency_corrections[cidx].value = 0;
-        o->stream->latency_corrections[cidx].corrupt = 0;
-    }
+        o->stream->current_write_index_correction = cidx;
+        o->stream->write_index_corrections[cidx].valid = 1;
+        o->stream->write_index_corrections[cidx].tag = tag;
+        o->stream->write_index_corrections[cidx].absolute = 0;
+        o->stream->write_index_corrections[cidx].value = 0;
+        o->stream->write_index_corrections[cidx].corrupt = 0;
+    }
+    
+    pa_log("requesting update %u\n", tag);
     
     return pa_operation_ref(o);
 }
@@ -946,7 +1015,6 @@
 
 pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) {
     pa_operation *o;
-    pa_operation *lo;
     pa_tagstruct *t;
     uint32_t tag;
     
@@ -955,15 +1023,6 @@
     
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
-
-    if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) {
-        if (!s->corked && b) {
-            /* Refresh the interpolated data just befor pausing */
-            pa_stream_get_time(s, NULL);
-        } else if (s->corked && !b)
-            /* Unpausing */
-            pa_gettimeofday(&s->ipol_timestamp);
-    }
 
     s->corked = b;
     
@@ -978,9 +1037,9 @@
     pa_pstream_send_tagstruct(s->context->pstream, t);
     pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o);
 
-    if ((lo = pa_stream_update_timing_info(s, NULL, NULL)))
-        pa_operation_unref(lo);
-    
+    if (s->direction == PA_STREAM_PLAYBACK)
+        invalidate_indexes(s, 1, 0);
+
     return pa_operation_ref(o);
 }
 
@@ -1006,14 +1065,24 @@
 
 pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
     pa_operation *o;
-
+    
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
     
     if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) {
-        pa_operation *lo;
-
-        if ((lo = pa_stream_update_timing_info(s, NULL, NULL)))
-            pa_operation_unref(lo);
+
+        if (s->direction == PA_STREAM_PLAYBACK) {
+            if (s->write_index_corrections[s->current_write_index_correction].valid)
+                s->write_index_corrections[s->current_write_index_correction].corrupt = 1;
+        
+            if (s->timing_info_valid)
+                s->timing_info.write_index_corrupt = 1;
+
+            if (s->buffer_attr.prebuf > 0) 
+                invalidate_indexes(s, 1, 0);
+            else
+                request_auto_timing_update(s, 1);
+        } else
+            invalidate_indexes(s, 0, 1);
     }
     
     return o;
@@ -1023,14 +1092,11 @@
     pa_operation *o;
 
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE);
-
-    if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) {
-        pa_operation *lo;
-
-        if ((lo = pa_stream_update_timing_info(s, NULL, NULL)))
-            pa_operation_unref(lo);
-    }
-    
+    PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE);
+
+    if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata)))
+        invalidate_indexes(s, 1, 0);
+
     return o;
 }
 
@@ -1038,13 +1104,10 @@
     pa_operation *o;
     
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE);
-
-    if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) {
-        pa_operation *lo;
-
-        if ((lo = pa_stream_update_timing_info(s, NULL, NULL)))
-            pa_operation_unref(lo);
-    }
+    PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE);
+
+    if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata)))
+        invalidate_indexes(s, 1, 0);
     
     return o;
 }
@@ -1084,50 +1147,56 @@
     PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA);
-
-    if (s->flags & PA_STREAM_INTERPOLATE_TIMING && s->ipol_usec_valid )
+    PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.read_index_corrupt, PA_ERR_NODATA);
+    PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.write_index_corrupt, PA_ERR_NODATA);
+
+    if (s->flags & PA_STREAM_INTERPOLATE_TIMING && s->ipol_usec_valid)
         usec = s->ipol_usec;
     else {
         if (s->direction == PA_STREAM_PLAYBACK) {
             /* The last byte that was written into the output device
              * had this time value associated */
             usec = pa_bytes_to_usec(s->timing_info.read_index < 0 ? 0 : (uint64_t) s->timing_info.read_index, &s->sample_spec);
-            
-            /* Because the latency info took a little time to come
-             * to us, we assume that the real output time is actually
-             * a little ahead */
-            usec += s->timing_info.transport_usec;
-            
-            /* However, the output device usually maintains a buffer
-               too, hence the real sample currently played is a little
-               back  */
-            if (s->timing_info.sink_usec >= usec)
-                usec = 0;
-            else
-                usec -= s->timing_info.sink_usec;
+
+            if (!s->corked) {
+                /* Because the latency info took a little time to come
+                 * to us, we assume that the real output time is actually
+                 * a little ahead */
+                usec += s->timing_info.transport_usec;
+                
+                /* However, the output device usually maintains a buffer
+                   too, hence the real sample currently played is a little
+                   back  */
+                if (s->timing_info.sink_usec >= usec)
+                    usec = 0;
+                else
+                    usec -= s->timing_info.sink_usec;
+            }
             
         } else if (s->direction == PA_STREAM_RECORD) {
             /* The last byte written into the server side queue had
              * this time value associated */
             usec = pa_bytes_to_usec(s->timing_info.write_index < 0 ? 0 : (uint64_t) s->timing_info.write_index, &s->sample_spec);
-            
-            /* Add transport latency */
-            usec += s->timing_info.transport_usec;
-            
-            /* Add latency of data in device buffer */
-            usec += s->timing_info.source_usec;
-            
-            /* If this is a monitor source, we need to correct the
-             * time by the playback device buffer */
-            if (s->timing_info.sink_usec >= usec)
-                usec = 0;
-            else
-                usec -= s->timing_info.sink_usec;
+
+            if (!s->corked) {
+                /* Add transport latency */
+                usec += s->timing_info.transport_usec;
+                
+                /* Add latency of data in device buffer */
+                usec += s->timing_info.source_usec;
+                
+                /* If this is a monitor source, we need to correct the
+                 * time by the playback device buffer */
+                if (s->timing_info.sink_usec >= usec)
+                    usec = 0;
+                else
+                    usec -= s->timing_info.sink_usec;
+            }
         }
 
         if (s->flags & PA_STREAM_INTERPOLATE_TIMING) {
+            s->ipol_usec = usec;
             s->ipol_usec_valid = 1;
-            s->ipol_usec = usec;
         }
     }
 
@@ -1189,6 +1258,7 @@
     PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA);
     PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.write_index_corrupt, PA_ERR_NODATA);
+    PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.read_index_corrupt, PA_ERR_NODATA);
     
     if ((r = pa_stream_get_time(s, &t)) < 0)
         return r;




More information about the pulseaudio-commits mailing list