+
+/*
+ * generate audio, if no data is received from bridge
+ */
+
+void Psip::set_tone(const char *dir, const char *tone)
+{
+ Port::set_tone(dir, tone);
+
+ update_load();
+}
+
+void Psip::update_load(void)
+{
+ /* don't trigger load event if event already active */
+ if (p_s_loadtimer.active)
+ return;
+
+ /* don't start timer if ... */
+ if (!p_tone_name[0])
+ return;
+
+ p_s_next_tv_sec = 0;
+ schedule_timer(&p_s_loadtimer, 0, 0); /* no delay the first time */
+}
+
+static int load_timer(struct lcr_timer *timer, void *instance, int index)
+{
+ class Psip *psip = (class Psip *)instance;
+
+ /* stop timer if ... */
+ if (!psip->p_tone_name[0])
+ return 0;
+
+ psip->load_tx();
+
+ return 0;
+}
+
+#define SEND_SIP_LEN 160
+
+void Psip::load_tx(void)
+{
+ int diff;
+ struct timeval current_time;
+ int tosend = SEND_SIP_LEN, i;
+ unsigned char buf[SEND_SIP_LEN], *p = buf;
+
+ /* get elapsed */
+ gettimeofday(¤t_time, NULL);
+ if (!p_s_next_tv_sec) {
+ /* if timer expired the first time, set next expected timeout 160 samples in advance */
+ p_s_next_tv_sec = current_time.tv_sec;
+ p_s_next_tv_usec = current_time.tv_usec + SEND_SIP_LEN * 125;
+ if (p_s_next_tv_usec >= 1000000) {
+ p_s_next_tv_usec -= 1000000;
+ p_s_next_tv_sec++;
+ }
+ schedule_timer(&p_s_loadtimer, 0, SEND_SIP_LEN * 125);
+ } else {
+ diff = 1000000 * (current_time.tv_sec - p_s_next_tv_sec)
+ + (current_time.tv_usec - p_s_next_tv_usec);
+ if (diff < -SEND_SIP_LEN * 125 || diff > SEND_SIP_LEN * 125) {
+ /* if clock drifts too much, set next timeout event to current timer + 160 */
+ diff = 0;
+ p_s_next_tv_sec = current_time.tv_sec;
+ p_s_next_tv_usec = current_time.tv_usec + SEND_SIP_LEN * 125;
+ if (p_s_next_tv_usec >= 1000000) {
+ p_s_next_tv_usec -= 1000000;
+ p_s_next_tv_sec++;
+ }
+ } else {
+ /* if diff is positive, it took too long, so next timeout will be earlier */
+ p_s_next_tv_usec += SEND_SIP_LEN * 125;
+ if (p_s_next_tv_usec >= 1000000) {
+ p_s_next_tv_usec -= 1000000;
+ p_s_next_tv_sec++;
+ }
+ }
+ schedule_timer(&p_s_loadtimer, 0, SEND_SIP_LEN * 125 - diff);
+ }
+
+ /* copy tones */
+ if (p_tone_name[0]) {
+ tosend -= read_audio(p, tosend);
+ }
+ if (tosend) {
+ PERROR("buffer is not completely filled\n");
+ return;
+ }
+
+ p = buf;
+ for (i = 0; i < SEND_SIP_LEN; i++) {
+ *p = flip[*p];
+ p++;
+ }
+ /* transmit data via rtp */
+ rtp_send_frame(buf, SEND_SIP_LEN, (options.law=='a')?PAYLOAD_TYPE_ALAW:PAYLOAD_TYPE_ULAW);
+}
+