}
SCPY(p_name, portname);
SCPY(p_tone_dir, p_settings.tones_dir); // just to be sure
- p_clock = 0;
+ p_last_tv_sec = 0;
+ p_last_tv_msec = 0;
p_type = type;
p_serial = port_serial++;
p_debug_nothingtosend = 0;
/*
* read from the given file as specified in port_set_tone and return sample data
+ * silence is appended if sample ends, but only the number of samples with tones are returned
*/
int Port::read_audio(unsigned char *buffer, int length)
{
goto read_more;
done:
- return(length);
+ return(length-len);
+}
+
+
+/*
+ * dummy for transmit function, since this must be inherited
+ */
+void Port::transmit(unsigned char *buffer, int length, int tonelength)
+{
}
* process transmission clock */
int Port::handler(void)
{
- port
-
return(0);
}
set_tone(param->tone.dir,param->tone.name);
return(1);
- case MESSAGE_DATA:
-//printf("port=%s, epoint=%d\n",p_cardname, epoint->e_serial);
- mixer(param);
+ case MESSAGE_DATA: /* tx-data from upper layer */
+ fromup(param->data.data, param->data.len);
return(1);
case MESSAGE_VBOX_TONE: /* play tone of answering machine */
}
-/*
- * special function generate individual isdn debug logs
- */
-void Port::printisdn(char *fmt, ...)
-{
- char buffer[4096];
- char name[128];
- va_list args;
- FILE *fp;
-
- va_start(args,fmt);
- VUNPRINT(buffer,sizeof(buffer)-1,fmt,args);
- buffer[sizeof(buffer)-1]=0;
- va_end(args);
-
- PDEBUG_RUNTIME(NULL, 0, DEBUG_PORT, "PORT(%s serial=%ld): %s\n", p_name, p_serial, buffer);
- if (options.deb & DEBUG_LOG)
- {
- SPRINT(name, "%s/debug_%s.log", INSTALL_DATA, p_name);
- if (!(fp = fopen(name, "a")))
- return;
-
- fprintf(fp, "%04d.%02d.%02d %02d:%02d:%02d %s(%ld): %s", now_tm->tm_year+1900, now_tm->tm_mon+1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec, p_name, p_serial, buffer);
- fclose(fp);
- }
-}
-
-
/* wave header structure */
struct fmt {
unsigned short stereo; /* 1 = mono, 2 = stereo */
* written before close, because we do not know the size yet)
* type=1 record annoucement, type=0 record audio stream, type=2 record vbox
*/
-int Port::open_record(int type, int vbox, int skip, char *terminal, int anon_ignore, char *vbox_email, int vbox_email_file)
+int Port::open_record(int type, int vbox, int skip, char *extension, int anon_ignore, char *vbox_email, int vbox_email_file)
{
/* RIFFxxxxWAVEfmt xxxx(fmt-size)dataxxxx... */
char dummyheader[8+4+8+sizeof(fmt)+8];
char filename[256];
- if (!terminal)
+ if (!extension)
{
- PERROR("Port(%d) not a terminal\n", p_serial);
+ PERROR("Port(%d) not an extension\n", p_serial);
return(0);
}
- SCPY(p_record_extension, terminal);
+ SCPY(p_record_extension, extension);
p_record_anon_ignore = anon_ignore;
SCPY(p_record_vbox_email, vbox_email);
p_record_vbox_email_file = vbox_email_file;
else
SPRINT(filename, "%s_%s-%s.isdn", p_record_filename, callerid, number);
break;
-
- default:
- if (p_record_vbox == 1)
- SPRINT(filename, "%s.unknown", p_record_filename);
- else
- SPRINT(filename, "%s_%s-%s.unknown", p_record_filename, callerid, number);
}
fclose(p_record);
}
+/*
+ * recording function
+ * Records all data from down and from up into one single stream.
+ * Both streams may have gaps or jitter.
+ * A Jitter buffer for both streams is used to compensate jitter.
+ *
+ * If one stream (dir) received packets, they are stored to a
+ * buffer to wait for the other stream (dir), so both streams can
+ * be combined. If the buffer is full, it's read pointer is written
+ * without mixing stream.
+ * A flag is used to indicate what stream is currently in buffer.
+ *
+ * NOTE: First stereo sample (odd) is from down, second is from up.
+ */
+alle buffer initialisieren
+record nur aufrufen, wenn recorded wird.
+restlicher buffer wegschreiben beim schliessen
+void Port::record(char *data, int length, int dir_fromup)
+{
+ unsigned char write_buffer[1024], *d;
+ signed short *s;
+ int r, w;
+ signed long sample;
+
+ /* no recording */
+ if (!p_record || !length)
+ return;
+
+ free = ((p_record_buffer_readp - p_record_buffer_writep - 1) & RECORD_BUFFER_MASK);
+
+ /* the buffer stores the same data stream */
+ if (dir_fromup == p_record_buffer_dir)
+ {
+ same_again:
+
+ /* first write what we can to the buffer */
+ while(free && length)
+ {
+ p_record_buffer[p_record_buffer_writep] = audio_law_to_s32(*data++);
+ p_record_buffer_writep = (p_record_buffer_writep + 1) & RECORD_BUFFER_MASK;
+ free--;
+ length--;
+ }
+ /* all written, so we return */
+ if (!length)
+ return;
+ /* still data left, buffer is full, so we need to write to file */
+ switch(p_record_type)
+ {
+ case CODEC_MONO:
+ s = (signed short *)write_buffer;
+ i = 0;
+ while(i < 256)
+ {
+ *s++ = p_record_buffer[p_record_buffer_readp];
+ p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK;
+ i++;
+ }
+ fwrite(write_buffer, 512, 1, p_record);
+ break;
+
+ case CODEC_STEREO:
+ s = (signed short *)write_buffer;
+ if (p_record_buffer_dir)
+ {
+ i = 0;
+ while(i < 256)
+ {
+ *s++ = 0; /* nothing from down */
+ *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 < 256)
+ {
+ *s++ = p_record_buffer[p_record_buffer_readp];
+ *s++ = 0; /* nothing from up */
+ p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK;
+ i++;
+ }
+ }
+ fwrite(write_buffer, 1024, 1, p_record);
+ break;
+
+ case CODEC_8BIT:
+ d = write_buffer;
+ i = 0;
+ while(i < 256)
+ {
+ *d++ = (p_record_buffer[p_record_buffer_readp]+0x8000) >> 8;
+ p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK;
+ i++;
+ }
+ fwrite(write_buffer, 512, 1, p_record);
+ break;
+
+ 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++;
+ }
+ fwrite(write_buffer, 256, 1, p_record);
+ break;
+ }
+ /* because we still have data, we write again */
+ free += sizeof(write_buffer);
+ goto same_again;
+ }
+
+ /* the buffer store 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;
+ /* 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 < 32767)
+ sample = -32767;
+ if (sample > 32768)
+ sample = 32768;
+ *s++ = sample;
+ i++;
+ }
+ fwrite(write_buffer, ii<<1, 1, p_record);
+ 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++);
+ i++;
+ }
+ }
+ fwrite(write_buffer, ii<<2, 1, p_record);
+ 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 < 32767)
+ sample = -32767;
+ if (sample > 32768)
+ sample = 32768;
+ *d++ = (sample+0x8000) >> 8;
+ i++;
+ }
+ fwrite(write_buffer, ii, 1, p_record);
+ 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 < 32767)
+ sample = -32767;
+ if (sample > 32768)
+ sample = 32768;
+ *d++ = audio_s16_to_law[sample & 0xffff];
+ i++;
+ }
+ fwrite(write_buffer, ii, 1, p_record);
+ break;
+ }
+ length -= ii;
+ /* data, but buffer empty */
+ if (length)
+ {
+ p_record_buffer_dir = dir_fromup;
+ goto same_again;
+ }
+ /* no data (maybe buffer) */
+ return;
+
+}
+
+
+/*
+ * enque data from upper buffer
+ */
+iniialisieren der werte
+void Port::txfromup(unsigned char *data, int length)
+{
+
+ /* no recording */
+ if (!length)
+ return;
+
+ /* get free samples in buffer */
+ free = ((p_fromup_buffer_readp - p_fromup_buffer_writep - 1) & FROMUP_BUFFER_MASK);
+ if (free < length)
+ {
+ PDEBUG(DEBUG_PORT, "Port(%d): fromup_buffer overflows, this shall not happen under normal conditions\n", p_serial);
+ return;
+ }
+
+ /* write data to buffer and return */
+ while(length)
+ {
+ p_fromup_buffer[p_fromup_buffer_writep] = *data++;
+ p_fromup_buffer_writep = (p_fromup_buffer_writep + 1) & FROMUP_BUFFER_MASK;
+ length--;
+ }
+ return; // must return, because length is 0
+}