1
/* $Id: mem_player.c 3664 2011-07-19 03:42:28Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
20
#include <pjmedia/mem_port.h>
21
#include <pj/assert.h>
26
#define THIS_FILE "mem_player.c"
28
#define SIGNATURE PJMEDIA_SIG_PORT_MEM_PLAYER
29
#define BYTES_PER_SAMPLE 2
36
pj_timestamp timestamp;
44
pj_status_t (*cb)(pjmedia_port *port,
50
static pj_status_t mem_put_frame(pjmedia_port *this_port,
51
pjmedia_frame *frame);
52
static pj_status_t mem_get_frame(pjmedia_port *this_port,
53
pjmedia_frame *frame);
54
static pj_status_t mem_on_destroy(pjmedia_port *this_port);
57
PJ_DEF(pj_status_t) pjmedia_mem_player_create( pj_pool_t *pool,
61
unsigned channel_count,
62
unsigned samples_per_frame,
63
unsigned bits_per_sample,
65
pjmedia_port **p_port )
67
struct mem_player *port;
68
pj_str_t name = pj_str("memplayer");
71
PJ_ASSERT_RETURN(pool && buffer && size && clock_rate && channel_count &&
72
samples_per_frame && bits_per_sample && p_port,
75
/* Can only support 16bit PCM */
76
PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);
79
port = PJ_POOL_ZALLOC_T(pool, struct mem_player);
80
PJ_ASSERT_RETURN(port != NULL, PJ_ENOMEM);
83
pjmedia_port_info_init(&port->base.info, &name, SIGNATURE, clock_rate,
84
channel_count, bits_per_sample, samples_per_frame);
86
port->base.put_frame = &mem_put_frame;
87
port->base.get_frame = &mem_get_frame;
88
port->base.on_destroy = &mem_on_destroy;
92
port->buffer = port->read_pos = (char*)buffer;
93
port->buf_size = size;
96
port->options = options;
98
*p_port = &port->base;
106
* Register a callback to be called when the file reading has reached the
109
PJ_DEF(pj_status_t) pjmedia_mem_player_set_eof_cb( pjmedia_port *port,
111
pj_status_t (*cb)(pjmedia_port *port,
114
struct mem_player *player;
116
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE,
119
player = (struct mem_player*) port;
120
player->user_data = user_data;
127
static pj_status_t mem_put_frame( pjmedia_port *this_port,
128
pjmedia_frame *frame)
130
PJ_UNUSED_ARG(this_port);
131
PJ_UNUSED_ARG(frame);
137
static pj_status_t mem_get_frame( pjmedia_port *this_port,
138
pjmedia_frame *frame)
140
struct mem_player *player;
142
pj_size_t size_needed, size_written;
144
PJ_ASSERT_RETURN(this_port->info.signature == SIGNATURE,
147
player = (struct mem_player*) this_port;
150
pj_status_t status = PJ_SUCCESS;
152
/* Call callback, if any */
154
status = (*player->cb)(this_port, player->user_data);
156
/* If callback returns non PJ_SUCCESS or 'no loop' is specified
157
* return immediately (and don't try to access player port since
158
* it might have been destroyed by the callback).
160
if ((status != PJ_SUCCESS) || (player->options & PJMEDIA_MEM_NO_LOOP)) {
161
frame->type = PJMEDIA_FRAME_TYPE_NONE;
165
player->eof = PJ_FALSE;
168
size_needed = PJMEDIA_PIA_AVG_FSZ(&this_port->info);
170
endpos = player->buffer + player->buf_size;
172
while (size_written < size_needed) {
173
char *dst = ((char*)frame->buf) + size_written;
176
max = size_needed - size_written;
177
if (endpos - player->read_pos < (int)max)
178
max = endpos - player->read_pos;
180
pj_memcpy(dst, player->read_pos, max);
182
player->read_pos += max;
184
pj_assert(player->read_pos <= endpos);
186
if (player->read_pos == endpos) {
188
player->eof = PJ_TRUE;
189
/* Reset read pointer */
190
player->read_pos = player->buffer;
192
/* Pad with zeroes then return for no looped play */
193
if (player->options & PJMEDIA_MEM_NO_LOOP) {
196
null_len = size_needed - size_written;
197
pj_bzero(dst + max, null_len);
203
frame->size = PJMEDIA_PIA_AVG_FSZ(&this_port->info);
204
frame->timestamp.u64 = player->timestamp.u64;
205
frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
207
player->timestamp.u64 += PJMEDIA_PIA_SPF(&this_port->info);
213
static pj_status_t mem_on_destroy(pjmedia_port *this_port)
215
PJ_ASSERT_RETURN(this_port->info.signature == SIGNATURE,
218
/* Destroy signature */
219
this_port->info.signature = 0;