On 16.02.2018 17:37, Raman Shishniou wrote: > > On 02/16/2018 12:00 PM, Georg Chini wrote: >> On 14.02.2018 23:16, Raman Shyshniou wrote: >>> Currently the pipe-source does not produce any data if no >>> writer is connected. This patch enable silence generator >>> when last writer closed pipe. It will stop automatically >>> when any data appears. >>> --- >> After my fixes to module-null-source, I think your logic is not yet >> completely correct. I would propose to do it like that: >> >> In source_process_msg(): >> >> case PA_SOURCE_MESSAGE_GET_LATENCY: >> current_latency = now - time stamp >> if (u->corkfd < 0) >> current_latency += data in pipe >> >> case PA_SOURCE_MESSAGE_SET_STATE: >> if (SUSPENDED or INIT -> IDLE || SUSPENDED or INIT -> RUNNING) { >> get time stamp >> u->starting = true >> } >> >> In thread_func(): >> >> close u->corkfd >> u->corkfd = -1 >> u->starting = true >> >> timer_elapsed = false >> revents = 0 >> get time stamp >> >> for (;;) { >> if (source is open) { >> >> /* We have to wait at least one configured source latency before starting >> * to read data */ >> if (revents & POLLIN && !u->starting) { >> read data from pipe >> if (u->corkfd >=0) { >> close corkfd >> u->corkfd = -1 >> } >> >> } else if (timer_elapsed && u->corkfd > 0) >> generate silence >> >> if (data was read/generated) { >> post data >> time stamp += data written >> } >> >> set timer absolute time stamp + configured (or fixed) source latency >> } else >> set timer disabled >> >> run rtpoll >> get timer_elapsed >> >> if (u->starting && timer_elapsed) >> u->starting = false >> >> if (revents & POLLHUP) { >> open pipe for writing >> u->corkfd = write file descriptor >> revents = revents & ~POLLHUP >> } >> >> error check >> } >> >> You can also add a source_update_requested_latency_cb() like >> in module-null-source and pass PA_SOURCE_DYNAMIC_LATENCY >> to pa_source_new() to make the latency configurable. >> >> I hope I did not forget anything ... > The incoming data can has a sample rate that differs from the system clock. > For example, due to imperfect hardware oscillator. It's a bad idea to expect > a data at the system clock rate. When the source is receiving a real data from > pipe the timer should be disabled and u->timestamp and u->starting doesn't make sense. You don't rely on the timer when data is coming from the pipe. The rtpollrun will return as soon as data is available in the pipe and then the timer expiration time will be moved forward. You are right, if the clocks do not match, the timer will expire sooner or later, before data is available in the pipe. This does not matter however because there is no data available and corkfd is < 0, it will just be an iteration without any action. You can anyway not expect that the thread is only woken up when the timer expires or something happens on the pipe side. The thread is also woken up when messages are sent to it. I agree that the timer can be disabled and that the time stamp gets meaningless the way it is set now when reading from the pipe. But we must continue without interruption when we switch from pipe to silence, so we should set the time stamp to something meaningful before switching to silence. (Switching between pipe and silence properly would not have worked with my code above.) Also I still believe that waiting one pipe fill time before reading the first data from the pipe will increase stability because then there is a larger buffer. When switching between pipe and silence, we have to wait until pipe data or silence runs out, otherwise we will supply too many samples. I have made another attempt on some pseudo-code, hope it is better this time: for (;;) {    if (source is open) {        /* We wait one configured source latency before starting         * to read data to improve stability */        if (revents & POLLIN && !u->starting) {            if (u->corkfd >=0) {                close corkfd                u->corkfd = -1                /* Let's wait until we run out of silence before                 * sending pipe data */                u->starting = true           } else {                read data from pipe                /* This is the time when we will run out of data */                time stamp = now + data to write          }       } else if (timer_elapsed && u->corkfd >= 0) {            generate silence (amount now - timestamp)            time stamp += data to write      }       if (data was read/generated)           post data       if (starting || u->corkfd >= 0)          set timer absolute time stamp + fixed source latency       else          set timer disabled   } else       set timer disabled   run rtpoll   get timer_elapsed    if (u->starting && timer_elapsed)        u->starting = false   if (revents & POLLHUP && u->corkfd < 0) {       open pipe for writing       u->corkfd = write file descriptor       revents = revents & ~(POLLHUP|POLLIN)       timer_elapsed = true       /* Time left to play for remaining pipe data */       delta = 0       if (time stamp > now)           delta = timestamp - now       /* If there is some data left in the pipe, we could post        * it here and add the amount to delta */       time stamp = now + delta - fixed source latency   }   error check }