~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjmedia/src/pjmedia/wav_player.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

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