sip-lab 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +38 -0
  2. package/a.js +280 -0
  3. package/binding.gyp +101 -0
  4. package/devjournal +435 -0
  5. package/index.js +68 -0
  6. package/install.sh +32 -0
  7. package/package.json +30 -0
  8. package/samples/late_negotiation.js +278 -0
  9. package/samples/simple.js +280 -0
  10. package/samples/sip_cancel.js +111 -0
  11. package/src/Makefile +42 -0
  12. package/src/README +3 -0
  13. package/src/addon.cpp +1418 -0
  14. package/src/event_templates.cpp +55 -0
  15. package/src/event_templates.hpp +27 -0
  16. package/src/idmanager.cpp +76 -0
  17. package/src/idmanager.hpp +26 -0
  18. package/src/log.cpp +18 -0
  19. package/src/log.hpp +15 -0
  20. package/src/packetdumper.cpp +234 -0
  21. package/src/packetdumper.hpp +67 -0
  22. package/src/pjmedia/Makefile +37 -0
  23. package/src/pjmedia/devjournal +26 -0
  24. package/src/pjmedia/include/chainlink/README +3 -0
  25. package/src/pjmedia/include/chainlink/chainlink.h +11 -0
  26. package/src/pjmedia/include/chainlink/chainlink_dtmfdet.h +56 -0
  27. package/src/pjmedia/include/chainlink/chainlink_tonegen.h +178 -0
  28. package/src/pjmedia/include/chainlink/chainlink_wav_port.h +231 -0
  29. package/src/pjmedia/include/chainlink/chainlink_wire_port.h +50 -0
  30. package/src/pjmedia/include/pjmedia/README +3 -0
  31. package/src/pjmedia/include/pjmedia/dtmfdet.h +74 -0
  32. package/src/pjmedia/src/chainlink/chainlink_dtmfdet.c +125 -0
  33. package/src/pjmedia/src/chainlink/chainlink_tonegen.c +901 -0
  34. package/src/pjmedia/src/chainlink/chainlink_wav_player.c +688 -0
  35. package/src/pjmedia/src/chainlink/chainlink_wav_writer.c +442 -0
  36. package/src/pjmedia/src/chainlink/chainlink_wire_port.c +93 -0
  37. package/src/pjmedia/src/pjmedia/dtmfdet.c +129 -0
  38. package/src/pjmedia/src/pjmedia/simpleua_dtmfdet.c +753 -0
  39. package/src/pjmedia/src/pjmedia/tonegen_dtmfdet.c +263 -0
  40. package/src/sip.cpp +4891 -0
  41. package/src/sip.hpp +64 -0
@@ -0,0 +1,688 @@
1
+ #include "chainlink.h"
2
+ #include "chainlink_wav_port.h"
3
+
4
+ #include <pjmedia/wav_port.h>
5
+ #include <pjmedia/alaw_ulaw.h>
6
+ #include <pjmedia/errno.h>
7
+ #include <pjmedia/wave.h>
8
+ #include <pj/assert.h>
9
+ #include <pj/file_access.h>
10
+ #include <pj/file_io.h>
11
+ #include <pj/log.h>
12
+ #include <pj/pool.h>
13
+ #include <pj/string.h>
14
+
15
+
16
+ #define THIS_FILE "chainlink_wav_player.c"
17
+
18
+
19
+ #define SIGNATURE PJMEDIA_SIGNATURE('L', 'w', 'p', 'l')
20
+ #define BITS_PER_SAMPLE 16
21
+
22
+ #if 1
23
+ # define TRACE_(x) PJ_LOG(4,x)
24
+ #else
25
+ # define TRACE_(x)
26
+ #endif
27
+
28
+ #if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
29
+ static void samples_to_host(pj_int16_t *samples, unsigned count)
30
+ {
31
+ unsigned i;
32
+ for (i=0; i<count; ++i) {
33
+ samples[i] = pj_swap16(samples[i]);
34
+ }
35
+ }
36
+ #else
37
+ # define samples_to_host(samples,count)
38
+ #endif
39
+
40
+ struct file_reader_port
41
+ {
42
+ struct chainlink link;
43
+ unsigned options;
44
+ pjmedia_wave_fmt_tag fmt_tag;
45
+ pj_uint16_t bytes_per_sample;
46
+ pj_bool_t eof;
47
+ pj_size_t bufsize;
48
+ char *buf;
49
+ char *readpos;
50
+ char *eofpos;
51
+
52
+ pj_off_t fsize;
53
+ unsigned start_data;
54
+ unsigned data_len;
55
+ unsigned data_left;
56
+ pj_off_t fpos;
57
+ pj_oshandle_t fd;
58
+
59
+ pj_status_t (*cb)(pjmedia_port*, void*);
60
+ };
61
+
62
+ static pj_status_t file_put_frame(pjmedia_port *this_port,
63
+ pjmedia_frame *frame);
64
+
65
+ static pj_status_t file_get_frame(pjmedia_port *this_port,
66
+ pjmedia_frame *frame);
67
+ static pj_status_t file_on_destroy(pjmedia_port *this_port);
68
+
69
+ static struct file_reader_port *create_file_port(pj_pool_t *pool)
70
+ {
71
+ const pj_str_t name = pj_str("file");
72
+ struct file_reader_port *port;
73
+
74
+ port = PJ_POOL_ZALLOC_T(pool, struct file_reader_port);
75
+ if (!port)
76
+ return NULL;
77
+
78
+ /* Put in default values.
79
+ * These will be overriden once the file is read.
80
+ */
81
+ pjmedia_port_info_init(&port->link.port.info, &name, SIGNATURE,
82
+ 8000, 1, 16, 80);
83
+
84
+ port->link.port.get_frame = &file_get_frame;
85
+ port->link.port.put_frame = &file_put_frame;
86
+ port->link.port.on_destroy = &file_on_destroy;
87
+
88
+
89
+ return port;
90
+ }
91
+
92
+ /*
93
+ * Fill buffer.
94
+ */
95
+ static pj_status_t fill_buffer(struct file_reader_port *fport)
96
+ {
97
+ pj_ssize_t size_left = fport->bufsize;
98
+ unsigned size_to_read;
99
+ pj_ssize_t size;
100
+ pj_status_t status;
101
+
102
+ fport->eofpos = NULL;
103
+
104
+ while (size_left > 0) {
105
+
106
+ /* Calculate how many bytes to read in this run. */
107
+ size = size_to_read = size_left;
108
+ status = pj_file_read(fport->fd,
109
+ &fport->buf[fport->bufsize-size_left],
110
+ &size);
111
+ if (status != PJ_SUCCESS)
112
+ return status;
113
+ if (size < 0) {
114
+ /* Should return more appropriate error code here.. */
115
+ return PJ_ECANCELLED;
116
+ }
117
+
118
+ if (size > (pj_ssize_t)fport->data_left) {
119
+ /* We passed the end of the data chunk,
120
+ * only count the portion read from the data chunk.
121
+ */
122
+ size = (pj_ssize_t)fport->data_left;
123
+ }
124
+
125
+ size_left -= size;
126
+ fport->data_left -= size;
127
+ fport->fpos += size;
128
+
129
+ /* If size is less than size_to_read, it indicates that we've
130
+ * encountered EOF. Rewind the file.
131
+ */
132
+ if (size < (pj_ssize_t)size_to_read) {
133
+ fport->eof = PJ_TRUE;
134
+ fport->eofpos = fport->buf + fport->bufsize - size_left;
135
+
136
+ if (fport->options & CHAINLINK_FILE_NO_LOOP) {
137
+ /* Zero remaining buffer */
138
+ if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_PCM) {
139
+ pj_bzero(fport->eofpos, size_left);
140
+ } else if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW) {
141
+ int val = pjmedia_linear2ulaw(0);
142
+ pj_memset(fport->eofpos, val, size_left);
143
+ } else if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ALAW) {
144
+ int val = pjmedia_linear2alaw(0);
145
+ pj_memset(fport->eofpos, val, size_left);
146
+ }
147
+ size_left = 0;
148
+ }
149
+
150
+ /* Rewind file */
151
+ fport->fpos = fport->start_data;
152
+ pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET);
153
+ fport->data_left = fport->data_len;
154
+ }
155
+ }
156
+
157
+ /* Convert samples to host rep */
158
+ samples_to_host((pj_int16_t*)fport->buf,
159
+ fport->bufsize/fport->bytes_per_sample);
160
+
161
+ return PJ_SUCCESS;
162
+ }
163
+
164
+
165
+ /*
166
+ * Create WAVE player port.
167
+ */
168
+ PJ_DEF(pj_status_t) chainlink_wav_player_port_create( pj_pool_t *pool,
169
+ const char *filename,
170
+ unsigned ptime,
171
+ unsigned options,
172
+ pj_ssize_t buff_size,
173
+ pjmedia_port **p_port )
174
+ {
175
+ pjmedia_wave_hdr wave_hdr;
176
+ pj_ssize_t size_to_read, size_read;
177
+ struct file_reader_port *fport;
178
+ pjmedia_audio_format_detail *ad;
179
+ pj_off_t pos;
180
+ pj_str_t name;
181
+ unsigned samples_per_frame;
182
+ pj_status_t status = PJ_SUCCESS;
183
+
184
+
185
+ /* Check arguments. */
186
+ PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL);
187
+
188
+ /* Check the file really exists. */
189
+ if (!pj_file_exists(filename)) {
190
+ return PJ_ENOTFOUND;
191
+ }
192
+
193
+ /* Normalize ptime */
194
+ if (ptime == 0)
195
+ ptime = 20;
196
+
197
+ /* Normalize buff_size */
198
+ if (buff_size < 1) buff_size = PJMEDIA_FILE_PORT_BUFSIZE;
199
+
200
+
201
+ /* Create fport instance. */
202
+ fport = create_file_port(pool);
203
+ if (!fport) {
204
+ return PJ_ENOMEM;
205
+ }
206
+
207
+
208
+ /* Get the file size. */
209
+ fport->fsize = pj_file_size(filename);
210
+
211
+ /* Size must be more than WAVE header size */
212
+ if (fport->fsize <= sizeof(pjmedia_wave_hdr)) {
213
+ return PJMEDIA_ENOTVALIDWAVE;
214
+ }
215
+
216
+ /* Open file. */
217
+ status = pj_file_open( pool, filename, PJ_O_RDONLY, &fport->fd);
218
+ if (status != PJ_SUCCESS)
219
+ return status;
220
+
221
+ /* Read the file header plus fmt header only. */
222
+ size_read = size_to_read = sizeof(wave_hdr) - 8;
223
+ status = pj_file_read( fport->fd, &wave_hdr, &size_read);
224
+ if (status != PJ_SUCCESS) {
225
+ pj_file_close(fport->fd);
226
+ return status;
227
+ }
228
+ if (size_read != size_to_read) {
229
+ pj_file_close(fport->fd);
230
+ return PJMEDIA_ENOTVALIDWAVE;
231
+ }
232
+
233
+ /* Normalize WAVE header fields values from little-endian to host
234
+ * byte order.
235
+ */
236
+ pjmedia_wave_hdr_file_to_host(&wave_hdr);
237
+
238
+ /* Validate WAVE file. */
239
+ if (wave_hdr.riff_hdr.riff != PJMEDIA_RIFF_TAG ||
240
+ wave_hdr.riff_hdr.wave != PJMEDIA_WAVE_TAG ||
241
+ wave_hdr.fmt_hdr.fmt != PJMEDIA_FMT_TAG)
242
+ {
243
+ pj_file_close(fport->fd);
244
+ TRACE_((THIS_FILE,
245
+ "actual value|expected riff=%x|%x, wave=%x|%x fmt=%x|%x",
246
+ wave_hdr.riff_hdr.riff, PJMEDIA_RIFF_TAG,
247
+ wave_hdr.riff_hdr.wave, PJMEDIA_WAVE_TAG,
248
+ wave_hdr.fmt_hdr.fmt, PJMEDIA_FMT_TAG));
249
+ return PJMEDIA_ENOTVALIDWAVE;
250
+ }
251
+
252
+ /* Validate format and its attributes (i.e: bits per sample, block align) */
253
+ switch (wave_hdr.fmt_hdr.fmt_tag) {
254
+ case PJMEDIA_WAVE_FMT_TAG_PCM:
255
+ if (wave_hdr.fmt_hdr.bits_per_sample != 16 ||
256
+ wave_hdr.fmt_hdr.block_align != 2 * wave_hdr.fmt_hdr.nchan)
257
+ status = PJMEDIA_EWAVEUNSUPP;
258
+ break;
259
+
260
+ case PJMEDIA_WAVE_FMT_TAG_ALAW:
261
+ case PJMEDIA_WAVE_FMT_TAG_ULAW:
262
+ if (wave_hdr.fmt_hdr.bits_per_sample != 8 ||
263
+ wave_hdr.fmt_hdr.block_align != wave_hdr.fmt_hdr.nchan)
264
+ status = PJMEDIA_ENOTVALIDWAVE;
265
+ break;
266
+
267
+ default:
268
+ status = PJMEDIA_EWAVEUNSUPP;
269
+ break;
270
+ }
271
+
272
+ if (status != PJ_SUCCESS) {
273
+ pj_file_close(fport->fd);
274
+ return status;
275
+ }
276
+
277
+ fport->fmt_tag = (pjmedia_wave_fmt_tag)wave_hdr.fmt_hdr.fmt_tag;
278
+ fport->bytes_per_sample = (pj_uint16_t)
279
+ (wave_hdr.fmt_hdr.bits_per_sample / 8);
280
+
281
+ /* If length of fmt_header is greater than 16, skip the remaining
282
+ * fmt header data.
283
+ */
284
+ if (wave_hdr.fmt_hdr.len > 16) {
285
+ size_to_read = wave_hdr.fmt_hdr.len - 16;
286
+ status = pj_file_setpos(fport->fd, size_to_read, PJ_SEEK_CUR);
287
+ if (status != PJ_SUCCESS) {
288
+ pj_file_close(fport->fd);
289
+ return status;
290
+ }
291
+ }
292
+
293
+ /* Repeat reading the WAVE file until we have 'data' chunk */
294
+ for (;;) {
295
+ pjmedia_wave_subchunk subchunk;
296
+ size_read = 8;
297
+ status = pj_file_read(fport->fd, &subchunk, &size_read);
298
+ if (status != PJ_SUCCESS || size_read != 8) {
299
+ pj_file_close(fport->fd);
300
+ return PJMEDIA_EWAVETOOSHORT;
301
+ }
302
+
303
+ /* Normalize endianness */
304
+ PJMEDIA_WAVE_NORMALIZE_SUBCHUNK(&subchunk);
305
+
306
+ /* Break if this is "data" chunk */
307
+ if (subchunk.id == PJMEDIA_DATA_TAG) {
308
+ wave_hdr.data_hdr.data = PJMEDIA_DATA_TAG;
309
+ wave_hdr.data_hdr.len = subchunk.len;
310
+ break;
311
+ }
312
+
313
+ /* Otherwise skip the chunk contents */
314
+ size_to_read = subchunk.len;
315
+ status = pj_file_setpos(fport->fd, size_to_read, PJ_SEEK_CUR);
316
+ if (status != PJ_SUCCESS) {
317
+ pj_file_close(fport->fd);
318
+ return status;
319
+ }
320
+ }
321
+
322
+ /* Current file position now points to start of data */
323
+ status = pj_file_getpos(fport->fd, &pos);
324
+ fport->start_data = (unsigned)pos;
325
+ fport->data_len = wave_hdr.data_hdr.len;
326
+ fport->data_left = wave_hdr.data_hdr.len;
327
+
328
+ /* Validate length. */
329
+ if (wave_hdr.data_hdr.len > fport->fsize - fport->start_data) {
330
+ pj_file_close(fport->fd);
331
+ return PJMEDIA_EWAVEUNSUPP;
332
+ }
333
+ if (wave_hdr.data_hdr.len < ptime * wave_hdr.fmt_hdr.sample_rate *
334
+ wave_hdr.fmt_hdr.nchan / 1000)
335
+ {
336
+ pj_file_close(fport->fd);
337
+ return PJMEDIA_EWAVETOOSHORT;
338
+ }
339
+
340
+ /* It seems like we have a valid WAVE file. */
341
+
342
+ /* Initialize */
343
+ fport->options = options;
344
+
345
+ /* Update port info. */
346
+ ad = pjmedia_format_get_audio_format_detail(&fport->link.port.info.fmt, 1);
347
+ pj_strdup2(pool, &name, filename);
348
+ samples_per_frame = ptime * wave_hdr.fmt_hdr.sample_rate *
349
+ wave_hdr.fmt_hdr.nchan / 1000;
350
+ pjmedia_port_info_init(&fport->link.port.info, &name, SIGNATURE,
351
+ wave_hdr.fmt_hdr.sample_rate,
352
+ wave_hdr.fmt_hdr.nchan,
353
+ BITS_PER_SAMPLE,
354
+ samples_per_frame);
355
+
356
+ /* If file is shorter than buffer size, adjust buffer size to file
357
+ * size. Otherwise EOF callback will be called multiple times when
358
+ * fill_buffer() is called.
359
+ */
360
+ if (wave_hdr.data_hdr.len < (unsigned)buff_size)
361
+ buff_size = wave_hdr.data_hdr.len;
362
+
363
+ /* Create file buffer.
364
+ */
365
+ fport->bufsize = buff_size;
366
+
367
+
368
+ /* samples_per_frame must be smaller than bufsize (because get_frame()
369
+ * doesn't handle this case).
370
+ */
371
+ if (samples_per_frame * fport->bytes_per_sample >= fport->bufsize) {
372
+ pj_file_close(fport->fd);
373
+ return PJ_EINVAL;
374
+ }
375
+
376
+ /* Create buffer. */
377
+ fport->buf = (char*) pj_pool_alloc(pool, fport->bufsize);
378
+ if (!fport->buf) {
379
+ pj_file_close(fport->fd);
380
+ return PJ_ENOMEM;
381
+ }
382
+
383
+ fport->readpos = fport->buf;
384
+
385
+ /* Set initial position of the file. */
386
+ fport->fpos = fport->start_data;
387
+
388
+ /* Fill up the buffer. */
389
+ status = fill_buffer(fport);
390
+ if (status != PJ_SUCCESS) {
391
+ pj_file_close(fport->fd);
392
+ return status;
393
+ }
394
+
395
+ /* Done. */
396
+
397
+ *p_port = &fport->link.port;
398
+
399
+
400
+ PJ_LOG(4,(THIS_FILE,
401
+ "File player '%.*s' created: samp.rate=%d, ch=%d, bufsize=%uKB, "
402
+ "filesize=%luKB",
403
+ (int)fport->link.port.info.name.slen,
404
+ fport->link.port.info.name.ptr,
405
+ ad->clock_rate,
406
+ ad->channel_count,
407
+ fport->bufsize / 1000,
408
+ (unsigned long)(fport->fsize / 1000)));
409
+
410
+ return PJ_SUCCESS;
411
+ }
412
+
413
+
414
+ /*
415
+ * Get the data length, in bytes.
416
+ */
417
+ PJ_DEF(pj_ssize_t) chainlink_wav_player_get_len(pjmedia_port *port)
418
+ {
419
+ struct file_reader_port *fport;
420
+ pj_ssize_t size;
421
+
422
+ /* Sanity check */
423
+ PJ_ASSERT_RETURN(port, -PJ_EINVAL);
424
+
425
+ /* Check that this is really a player port */
426
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP);
427
+
428
+ fport = (struct file_reader_port*) port;
429
+
430
+ size = (pj_ssize_t) fport->fsize;
431
+ return size - fport->start_data;
432
+ }
433
+
434
+
435
+ /*
436
+ * Set position.
437
+ */
438
+ PJ_DEF(pj_status_t) chainlink_wav_player_port_set_pos(pjmedia_port *port,
439
+ pj_uint32_t bytes )
440
+ {
441
+ struct file_reader_port *fport;
442
+ pj_status_t status;
443
+
444
+ /* Sanity check */
445
+ PJ_ASSERT_RETURN(port, PJ_EINVAL);
446
+
447
+ /* Check that this is really a player port */
448
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVALIDOP);
449
+
450
+
451
+ fport = (struct file_reader_port*) port;
452
+
453
+ /* Check that this offset does not pass the audio-data (in case of
454
+ * extra chunk after audio data chunk
455
+ */
456
+ PJ_ASSERT_RETURN(bytes < fport->data_len, PJ_EINVAL);
457
+
458
+ fport->fpos = fport->start_data + bytes;
459
+ fport->data_left = fport->data_len - bytes;
460
+ pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET);
461
+
462
+ fport->eof = PJ_FALSE;
463
+ status = fill_buffer(fport);
464
+ if (status != PJ_SUCCESS)
465
+ return status;
466
+
467
+ fport->readpos = fport->buf;
468
+
469
+ return PJ_SUCCESS;
470
+ }
471
+
472
+
473
+ /*
474
+ * Get the file play position of WAV player.
475
+ */
476
+ PJ_DEF(pj_ssize_t) chainlink_wav_player_port_get_pos( pjmedia_port *port )
477
+ {
478
+ struct file_reader_port *fport;
479
+ pj_size_t payload_pos;
480
+
481
+ /* Sanity check */
482
+ PJ_ASSERT_RETURN(port, -PJ_EINVAL);
483
+
484
+ /* Check that this is really a player port */
485
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP);
486
+
487
+ fport = (struct file_reader_port*) port;
488
+
489
+ payload_pos = (pj_size_t)(fport->fpos - fport->start_data);
490
+ if (payload_pos >= fport->bufsize)
491
+ return payload_pos - fport->bufsize + (fport->readpos - fport->buf);
492
+ else
493
+ return (fport->readpos - fport->buf) % payload_pos;
494
+ }
495
+
496
+
497
+
498
+ /*
499
+ * Register a callback to be called when the file reading has reached the
500
+ * end of file.
501
+ */
502
+ PJ_DEF(pj_status_t) chainlink_wav_player_set_eof_cb( pjmedia_port *port,
503
+ void *user_data,
504
+ pj_status_t (*cb)(pjmedia_port *port,
505
+ void *usr_data))
506
+ {
507
+ struct file_reader_port *fport;
508
+
509
+ /* Sanity check */
510
+ PJ_ASSERT_RETURN(port, -PJ_EINVAL);
511
+
512
+ /* Check that this is really a player port */
513
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP);
514
+
515
+ fport = (struct file_reader_port*) port;
516
+
517
+ fport->link.port.port_data.pdata = user_data;
518
+ fport->cb = cb;
519
+
520
+ return PJ_SUCCESS;
521
+ }
522
+
523
+ static pj_status_t file_put_frame(pjmedia_port *this_port,
524
+ pjmedia_frame *frame)
525
+ {
526
+ PJ_ASSERT_RETURN(this_port && frame, PJ_EINVAL);
527
+
528
+ struct chainlink *link = (struct chainlink*)this_port;
529
+ PJ_ASSERT_RETURN(link->next, PJ_EINVAL);
530
+ PJ_ASSERT_RETURN(link->next->put_frame, PJ_EINVAL);
531
+
532
+ return link->next->put_frame(link->next, frame);
533
+ }
534
+
535
+ /*
536
+ * Get frame from file.
537
+ */
538
+ static pj_status_t file_get_frame(pjmedia_port *this_port,
539
+ pjmedia_frame *frame)
540
+ {
541
+ struct file_reader_port *fport = (struct file_reader_port*)this_port;
542
+ unsigned frame_size;
543
+ pj_status_t status;
544
+
545
+ pj_assert(fport->link.port.info.signature == SIGNATURE);
546
+ pj_assert(frame->size <= fport->bufsize);
547
+
548
+ /* EOF is set and readpos already passed the eofpos */
549
+ if (fport->eof && fport->readpos >= fport->eofpos) {
550
+ pj_status_t status = PJ_SUCCESS;
551
+
552
+ PJ_LOG(5,(THIS_FILE, "File port %.*s EOF",
553
+ (int)fport->link.port.info.name.slen,
554
+ fport->link.port.info.name.ptr));
555
+
556
+ /* Call callback, if any */
557
+ if (fport->cb)
558
+ status = (*fport->cb)(this_port, fport->link.port.port_data.pdata);
559
+
560
+ /* If callback returns non PJ_SUCCESS or 'no loop' is specified,
561
+ * return immediately (and don't try to access player port since
562
+ * it might have been destroyed by the callback).
563
+ */
564
+ if ((status != PJ_SUCCESS) || (fport->options & CHAINLINK_FILE_NO_LOOP)) {
565
+ frame->type = PJMEDIA_FRAME_TYPE_NONE;
566
+ frame->size = 0;
567
+ return PJ_EEOF;
568
+ }
569
+
570
+ PJ_LOG(5,(THIS_FILE, "File port %.*s rewinding..",
571
+ (int)fport->link.port.info.name.slen,
572
+ fport->link.port.info.name.ptr));
573
+
574
+ fport->eof = PJ_FALSE;
575
+ }
576
+
577
+ if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_PCM) {
578
+ frame_size = frame->size;
579
+ //frame->size = frame_size;
580
+ } else {
581
+ /* Must be ULAW or ALAW */
582
+ pj_assert(fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW ||
583
+ fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ALAW);
584
+
585
+ frame_size = frame->size >> 1;
586
+ frame->size = frame_size << 1;
587
+ }
588
+
589
+ /* Copy frame from buffer. */
590
+ frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
591
+ frame->timestamp.u64 = 0;
592
+
593
+ if ((fport->readpos + frame_size) <= (fport->buf + fport->bufsize))
594
+ {
595
+ /* Read contiguous buffer. */
596
+ pj_memcpy(frame->buf, fport->readpos, frame_size);
597
+
598
+ /* Fill up the buffer if all has been read. */
599
+ fport->readpos += frame_size;
600
+ if (fport->readpos == fport->buf + fport->bufsize) {
601
+ fport->readpos = fport->buf;
602
+
603
+ status = fill_buffer(fport);
604
+ if (status != PJ_SUCCESS) {
605
+ frame->type = PJMEDIA_FRAME_TYPE_NONE;
606
+ frame->size = 0;
607
+ fport->readpos = fport->buf + fport->bufsize;
608
+ return status;
609
+ }
610
+ }
611
+ } else {
612
+ unsigned endread;
613
+
614
+ /* Split read.
615
+ * First stage: read until end of buffer.
616
+ */
617
+ endread = (fport->buf+fport->bufsize) - fport->readpos;
618
+ pj_memcpy(frame->buf, fport->readpos, endread);
619
+
620
+ /* End Of Buffer and EOF and NO LOOP */
621
+ if (fport->eof && (fport->options & CHAINLINK_FILE_NO_LOOP)) {
622
+ fport->readpos += endread;
623
+
624
+ if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_PCM) {
625
+ pj_bzero((char*)frame->buf + endread, frame_size - endread);
626
+ } else if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW) {
627
+ int val = pjmedia_linear2ulaw(0);
628
+ pj_memset((char*)frame->buf + endread, val,
629
+ frame_size - endread);
630
+ } else if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ALAW) {
631
+ int val = pjmedia_linear2alaw(0);
632
+ pj_memset((char*)frame->buf + endread, val,
633
+ frame_size - endread);
634
+ }
635
+
636
+ return PJ_SUCCESS;
637
+ }
638
+
639
+ /* Second stage: fill up buffer, and read from the start of buffer. */
640
+ status = fill_buffer(fport);
641
+ if (status != PJ_SUCCESS) {
642
+ frame->type = PJMEDIA_FRAME_TYPE_NONE;
643
+ frame->size = 0;
644
+ fport->readpos = fport->buf + fport->bufsize;
645
+ return status;
646
+ }
647
+
648
+ pj_memcpy(((char*)frame->buf)+endread, fport->buf, frame_size-endread);
649
+ fport->readpos = fport->buf + (frame_size - endread);
650
+ }
651
+
652
+ if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW ||
653
+ fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ALAW)
654
+ {
655
+ unsigned i;
656
+ pj_uint16_t *dst;
657
+ pj_uint8_t *src;
658
+
659
+ dst = (pj_uint16_t*)frame->buf + frame_size - 1;
660
+ src = (pj_uint8_t*)frame->buf + frame_size - 1;
661
+
662
+ if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW) {
663
+ for (i = 0; i < frame_size; ++i) {
664
+ *dst-- = (pj_uint16_t) pjmedia_ulaw2linear(*src--);
665
+ }
666
+ } else {
667
+ for (i = 0; i < frame_size; ++i) {
668
+ *dst-- = (pj_uint16_t) pjmedia_alaw2linear(*src--);
669
+ }
670
+ }
671
+ }
672
+
673
+ return PJ_SUCCESS;
674
+ }
675
+
676
+ /*
677
+ * Destroy port.
678
+ */
679
+ static pj_status_t file_on_destroy(pjmedia_port *this_port)
680
+ {
681
+ struct file_reader_port *fport = (struct file_reader_port*) this_port;
682
+
683
+ pj_assert(this_port->info.signature == SIGNATURE);
684
+
685
+ pj_file_close(fport->fd);
686
+ return PJ_SUCCESS;
687
+ }
688
+