+ case CODEC_LAW:
+ d = write_buffer;
+ i = 0;
+ while(i < 256) {
+ *d++ = audio_s16_to_law[p_record_buffer[p_record_buffer_readp] & 0xffff];
+ p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK;
+ i++;
+ }
+ ret = fwrite(write_buffer, 256, 1, p_record);
+ p_record_length += 256;
+ break;
+ }
+ /* because we still have data, we write again */
+ free += 256;
+ goto same_again;
+ }
+ /* the buffer stores the other stream */
+
+different_again:
+ /* if buffer empty, change it */
+ if (p_record_buffer_readp == p_record_buffer_writep) {
+ p_record_buffer_dir = dir_fromup;
+ goto same_again;
+ }
+ /* how much data can we mix ? */
+ ii = (p_record_buffer_writep - p_record_buffer_readp) & RECORD_BUFFER_MASK;
+ if (length < ii)
+ ii = length;
+
+ if (ii > 256)
+ ii = 256;
+//printf("same ii=%d length=%d\n", ii, length);
+//PDEBUG(DEBUG_PORT, "record(data,%d,%d): free=%d, p_record_buffer_dir=%d, p_record_buffer_readp=%d, p_record_buffer_writep=%d: mixing %d bytes.\n", length, dir_fromup, free, p_record_buffer_dir, p_record_buffer_readp, p_record_buffer_writep, ii);
+
+ /* write data mixed with the buffer */
+ switch(p_record_type) {
+ case CODEC_MONO:
+ s = (signed short *)write_buffer;
+ i = 0;
+ while(i < ii) {
+ sample = p_record_buffer[p_record_buffer_readp]
+ + audio_law_to_s32[*data++];
+ p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK;
+ if (sample < SHORT_MIN) sample = SHORT_MIN;
+ if (sample > SHORT_MAX) sample = SHORT_MAX;
+ *s++ = sample;
+ i++;
+ }
+ ret = fwrite(write_buffer, ii<<1, 1, p_record);
+ p_record_length += (ii<<1);
+ break;
+
+ case CODEC_STEREO:
+ s = (signed short *)write_buffer;
+ if (p_record_buffer_dir) {
+ i = 0;
+ while(i < ii) {
+ *s++ = audio_law_to_s32[*data++];
+ *s++ = p_record_buffer[p_record_buffer_readp];
+ p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK;
+ i++;
+ }
+ } else {
+ i = 0;
+ while(i < ii) {
+ *s++ = p_record_buffer[p_record_buffer_readp];
+ *s++ = audio_law_to_s32[*data++];
+ p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK;
+ i++;
+ }
+ }
+ ret = fwrite(write_buffer, ii<<2, 1, p_record);
+ p_record_length += (ii<<2);
+ break;
+
+ case CODEC_8BIT:
+ d = write_buffer;
+ i = 0;
+ while(i < ii) {
+ sample = p_record_buffer[p_record_buffer_readp]
+ + audio_law_to_s32[*data++];
+ p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK;
+ if (sample < SHORT_MIN) sample = SHORT_MIN;
+ if (sample > SHORT_MAX) sample = SHORT_MAX;
+ *d++ = (sample+0x8000) >> 8;
+ i++;
+ }
+ ret = fwrite(write_buffer, ii, 1, p_record);
+ p_record_length += ii;
+ break;
+
+ case CODEC_LAW:
+ d = write_buffer;
+ i = 0;
+ while(i < ii) {
+ sample = p_record_buffer[p_record_buffer_readp]
+ + audio_law_to_s32[*data++];
+ p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK;
+ if (sample < SHORT_MIN) sample = SHORT_MIN;
+ if (sample > SHORT_MAX) sample = SHORT_MAX;
+ *d++ = audio_s16_to_law[sample & 0xffff];
+ i++;
+ }
+ ret = fwrite(write_buffer, ii, 1, p_record);
+ p_record_length += ii;
+ break;
+ }
+ length -= ii;
+ /* still data */
+ if (length)
+ goto different_again;
+ /* no data (maybe buffer) */
+ return;
+
+}
+
+void Port::tap(unsigned char *data, int length, int dir_fromup)
+{
+}
+
+void Port::update_rxoff(void)
+{
+}
+
+void Port::update_load(void)
+{
+}
+
+
+/*
+ * bridge handling
+ */
+
+int bridge_timeout(struct lcr_timer *timer, void *instance, int index);
+
+static void remove_bridge(struct port_bridge *bridge, class Port *port)
+{
+ struct port_bridge **temp = &p_bridge_first;
+ while (*temp) {
+ if (*temp == bridge) {
+ struct port_bridge_member **memberp = &bridge->first, *member;
+
+ /* loop until we are found */
+ while(*memberp) {
+ if ((*memberp)->port == port) {
+ member = *memberp;
+ *memberp = member->next;
+ FREE(member, sizeof(struct port_bridge_member));
+ memuse--;
+#ifndef TEST_CONFERENCE
+ if (bridge->first && bridge->first->next && !bridge->first->next->next) {
+#else
+ if (bridge->first && !bridge->first->next) {
+#endif
+ PDEBUG(DEBUG_PORT, "bridge %u is no conference anymore\n", bridge->bridge_id);
+ del_timer(&bridge->timer);
+ }
+ break;
+ }
+ memberp = &((*memberp)->next);
+ }
+ /* if bridge is empty, remove it */
+ if (bridge->first == NULL) {
+ PDEBUG(DEBUG_PORT, "Remove bridge %u\n", bridge->bridge_id);
+ *temp = bridge->next;
+ FREE(bridge, sizeof(struct port_bridge));
+ memuse--;
+ }
+ return;
+ }
+ temp = &((*temp)->next);
+ }
+ PERROR("Bridge %p not found in list\n", bridge);
+}
+
+void Port::bridge(unsigned int bridge_id)
+{
+ struct port_bridge_member **memberp;
+
+ /* Remove bridge, if we leave bridge or if we join a different bridge. */
+ if (p_bridge && bridge_id != p_bridge->bridge_id) {
+ PDEBUG(DEBUG_PORT, "Remove port %u from bridge %u, because out new bridge is %u\n", p_serial, p_bridge->bridge_id, bridge_id);
+ remove_bridge(p_bridge, this);
+ p_bridge = NULL;
+ }
+
+ /* if we leave bridge */
+ if (!bridge_id)
+ return;
+
+ /* find bridge */
+ if (!p_bridge) {
+ struct port_bridge *temp = p_bridge_first;
+
+ while (temp) {
+ if (temp->bridge_id == bridge_id)
+ break;
+ temp = temp->next;
+ }
+ p_bridge = temp;
+ if (p_bridge)
+ PDEBUG(DEBUG_PORT, "Port %d found existing bridge %u.\n", p_serial, p_bridge->bridge_id);
+ }
+
+ /* create bridge */
+ if (!p_bridge) {
+ struct port_bridge **temp = &p_bridge_first;
+
+ p_bridge = (struct port_bridge *) MALLOC(sizeof(struct port_bridge));
+ memuse++;
+ p_bridge->bridge_id = bridge_id;
+
+ /* attach bridge instance to list */
+ while (*temp)
+ temp = &((*temp)->next);
+ *temp = p_bridge;
+ PDEBUG(DEBUG_PORT, "Port %d creating not existing bridge %u.\n", p_serial, p_bridge->bridge_id);
+ }
+
+ /* attach to bridge */
+ memberp = &p_bridge->first;
+ while(*memberp) {
+ if ((*memberp)->port == this) {
+ /* already joined */
+ return;
+ }
+ memberp = &((*memberp)->next);
+ }
+ *memberp = (struct port_bridge_member *) MALLOC(sizeof(struct port_bridge_member));
+ memuse++;
+ (*memberp)->port = this;
+ /* check if bridge becomes a conference */
+#ifndef TEST_CONFERENCE
+ if (p_bridge->first->next && p_bridge->first->next->next && !p_bridge->first->next->next->next) {
+ p_bridge->first->next->next->write_p = 0;
+ p_bridge->first->next->next->min_space = 0;
+ memset(p_bridge->first->next->next->buffer, silence, sizeof((*memberp)->buffer));
+#else
+ if (p_bridge->first->next && !p_bridge->first->next->next) {
+#endif
+ p_bridge->first->next->write_p = 0;
+ p_bridge->first->next->min_space = 0;
+ memset(p_bridge->first->next->buffer, silence, sizeof((*memberp)->buffer));
+ p_bridge->first->write_p = 0;
+ p_bridge->first->min_space = 0;
+ memset(p_bridge->first->buffer, silence, sizeof((*memberp)->buffer));
+ memset(p_bridge->sum_buffer, 0, sizeof(p_bridge->sum_buffer));
+ p_bridge->read_p = 0;
+ add_timer(&p_bridge->timer, bridge_timeout, p_bridge, 0);
+ schedule_timer(&p_bridge->timer, 0, 20000); /* 20 MS */
+ p_bridge->sample_count = 0;
+ PDEBUG(DEBUG_PORT, "bridge %u became a conference\n", p_bridge->bridge_id);
+ }
+}
+
+/* send data to remote Port or add to sum buffer */
+int Port::bridge_tx(unsigned char *data, int len)
+{
+ int write_p, space;
+ struct port_bridge_member *member;
+ signed long *sum;
+ unsigned char *buf;
+
+#ifdef WITH_VOOTP
+ if (p_vootp)
+ vootp_encrypt_stream(p_vootp, data, len);
+#endif
+
+ /* less than two ports, so drop */
+ if (!p_bridge || !p_bridge->first || !p_bridge->first->next)
+ return -EIO;
+#ifndef TEST_CONFERENCE
+ /* two ports, so bridge */
+ if (!p_bridge->first->next->next) {
+ if (p_bridge->first->port == this)
+ return p_bridge->first->next->port->bridge_rx(data, len);
+ if (p_bridge->first->next->port == this)
+ return p_bridge->first->port->bridge_rx(data, len);
+ return -EINVAL;
+ }
+#endif
+ /* more than two ports... */
+ member = p_bridge->first;
+ while (member) {
+ if (member->port == this)
+ break;
+ member = member->next;
+ }
+ if (!member)
+ return -EINVAL;
+ write_p = member->write_p;
+ /* calculate space, so write pointer will not overrun (or reach) read pointer in ring buffer */
+ space = (p_bridge->read_p - write_p - 1) & (BRIDGE_BUFFER - 1);
+ /* clip len, if it does not fit */
+ if (space < len)
+ len = space;
+ /* apply audio samples to sum buffer */
+ sum = p_bridge->sum_buffer;
+ buf = member->buffer;
+ while (len--) {
+ sum[write_p] += audio_law_to_s32[*data];
+ buf[write_p] = *data++;
+ write_p = (write_p + 1) & (BRIDGE_BUFFER - 1);
+ }
+ /* raise write pointer */
+ member->write_p = write_p;
+
+ return 0;
+}
+
+int bridge_timeout(struct lcr_timer *timer, void *instance, int index)
+{
+ struct port_bridge *bridge = (struct port_bridge *)instance;
+ struct port_bridge_member *member = bridge->first;
+ unsigned long long timer_time;
+ signed long *sum, sample;
+ unsigned char buffer[160], *buf, *d;
+ int i, read_p, space;
+
+ bridge->sample_count += 160;
+
+ /* schedule exactly 20ms from last schedule */
+ timer_time = timer->timeout.tv_sec * MICRO_SECONDS + timer->timeout.tv_usec;
+ timer_time += 20000; /* 20 MS */
+ timer->timeout.tv_sec = timer_time / MICRO_SECONDS;
+ timer->timeout.tv_usec = timer_time % MICRO_SECONDS;
+ timer->active = 1;
+
+ while (member) {
+ /* calculate transmit data */
+ read_p = bridge->read_p;
+ sum = bridge->sum_buffer;
+ buf = member->buffer;
+ d = buffer;
+ for (i = 0; i < 160; i++) {
+ sample = sum[read_p];
+ sample -= audio_law_to_s32[buf[read_p]];
+ buf[read_p] = silence;
+ if (sample < SHORT_MIN) sample = SHORT_MIN;
+ if (sample > SHORT_MAX) sample = SHORT_MAX;
+ *d++ = audio_s16_to_law[sample & 0xffff];
+ read_p = (read_p + 1) & (BRIDGE_BUFFER - 1);
+ }
+ /* send data */
+ member->port->bridge_rx(buffer, 160);
+ /* raise write pointer, if read pointer would overrun them */
+ space = ((member->write_p - bridge->read_p) & (BRIDGE_BUFFER - 1)) - 160;
+ if (space < 0) {
+ space = 0;
+ member->write_p = read_p;
+// PDEBUG(DEBUG_PORT, "bridge %u member %d has buffer underrun\n", bridge->bridge_id, member->port->p_serial);
+ }
+ /* find minimum delay */
+ if (space < member->min_space)
+ member->min_space = space;
+ /* check if we should reduce buffer */
+ if (bridge->sample_count >= 8000*5) {
+ /* reduce buffer by minimum delay */
+// PDEBUG(DEBUG_PORT, "bridge %u member %d has min space of %d samples\n", bridge->bridge_id, member->port->p_serial, member->min_space);
+ member->write_p = (member->write_p - member->min_space) & (BRIDGE_BUFFER - 1);
+ member->min_space = 1000000; /* infinite */
+ }
+ member = member->next;
+ }
+
+ /* clear sample data */
+ read_p = bridge->read_p;
+ sum = bridge->sum_buffer;
+ for (i = 0; i < 160; i++) {
+ sum[read_p] = 0;
+ read_p = (read_p + 1) & (BRIDGE_BUFFER - 1);
+ }
+
+ /* raise read pointer */
+ bridge->read_p = read_p;
+
+ if (bridge->sample_count >= 8000*5)
+ bridge->sample_count = 0;
+
+ return 0;
+}
+
+
+/* receive data from remote Port */
+int Port::bridge_rx(unsigned char *data, int len)
+{
+
+#ifdef WITH_VOOTP
+ if (p_vootp)
+ vootp_decrypt_stream(p_vootp, data, len);
+#endif
+
+ return 0;
+}
+
+#ifdef WITH_VOOTP
+static void vootp_info(void *priv, const char *text)
+{
+ class Port *port = (class Port *)priv;
+ char display[strlen(text) + 1];
+
+ SCPY(display, text);
+ if (display[0])
+ display[strlen(display) - 1] = '\0';
+
+ port->set_display(display);
+}
+
+void Port::set_vootp(struct param_vootp *vootp)
+{
+ if (p_vootp) {
+ vootp_destroy(p_vootp);
+ p_vootp = NULL;
+ }
+ if (vootp->enable) {
+ p_vootp = vootp_create(this, (options.law=='a'), options.otp_dir, NULL, NULL, vootp->id, vootp_info);
+// vootp_loglevel(VOOTP_LOGL_DEBUG);
+ if (!p_vootp) {
+ struct lcr_msg *message;
+
+ message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_VOOTP);
+ message->param.vootp.failed = 1;
+ message_put(message);
+ }
+ }
+}
+#endif