1
/* $Id: master_port.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/master_port.h>
21
#include <pjmedia/clock.h>
22
#include <pjmedia/errno.h>
23
#include <pj/assert.h>
26
#include <pj/string.h>
29
struct pjmedia_master_port
41
static void clock_callback(const pj_timestamp *ts, void *user_data);
45
* Create a master port.
48
PJ_DEF(pj_status_t) pjmedia_master_port_create( pj_pool_t *pool,
52
pjmedia_master_port **p_m)
54
pjmedia_master_port *m;
56
unsigned channel_count;
57
unsigned samples_per_frame;
58
unsigned bytes_per_frame;
59
pjmedia_audio_format_detail *u_afd, *d_afd;
63
PJ_ASSERT_RETURN(pool && u_port && d_port && p_m, PJ_EINVAL);
65
u_afd = pjmedia_format_get_audio_format_detail(&u_port->info.fmt, PJ_TRUE);
66
d_afd = pjmedia_format_get_audio_format_detail(&d_port->info.fmt, PJ_TRUE);
68
/* Both ports MUST have equal clock rate */
69
PJ_ASSERT_RETURN(u_afd->clock_rate == d_afd->clock_rate,
70
PJMEDIA_ENCCLOCKRATE);
72
/* Both ports MUST have equal samples per frame */
73
PJ_ASSERT_RETURN(PJMEDIA_PIA_SPF(&u_port->info)==
74
PJMEDIA_PIA_SPF(&d_port->info),
75
PJMEDIA_ENCSAMPLESPFRAME);
77
/* Both ports MUST have equal channel count */
78
PJ_ASSERT_RETURN(u_afd->channel_count == d_afd->channel_count,
82
/* Get clock_rate and samples_per_frame from one of the port. */
83
clock_rate = u_afd->clock_rate;
84
samples_per_frame = PJMEDIA_PIA_SPF(&u_port->info);
85
channel_count = u_afd->channel_count;
88
/* Get the bytes_per_frame value, to determine the size of the
89
* buffer. We take the larger size of the two ports.
91
bytes_per_frame = PJMEDIA_AFD_AVG_FSZ(u_afd);
92
if (PJMEDIA_AFD_AVG_FSZ(d_afd) > bytes_per_frame)
93
bytes_per_frame = PJMEDIA_AFD_AVG_FSZ(d_afd);
96
/* Create the master port instance */
97
m = PJ_POOL_ZALLOC_T(pool, pjmedia_master_port);
104
m->buff_size = bytes_per_frame;
105
m->buff = pj_pool_alloc(pool, m->buff_size);
109
/* Create lock object */
110
status = pj_lock_create_simple_mutex(pool, "mport", &m->lock);
111
if (status != PJ_SUCCESS)
114
/* Create media clock */
115
status = pjmedia_clock_create(pool, clock_rate, channel_count,
116
samples_per_frame, options, &clock_callback,
118
if (status != PJ_SUCCESS) {
119
pj_lock_destroy(m->lock);
131
* Start the media flow.
133
PJ_DEF(pj_status_t) pjmedia_master_port_start(pjmedia_master_port *m)
135
PJ_ASSERT_RETURN(m && m->clock, PJ_EINVAL);
136
PJ_ASSERT_RETURN(m->u_port && m->d_port, PJ_EINVALIDOP);
138
return pjmedia_clock_start(m->clock);
143
* Stop the media flow.
145
PJ_DEF(pj_status_t) pjmedia_master_port_stop(pjmedia_master_port *m)
147
PJ_ASSERT_RETURN(m && m->clock, PJ_EINVAL);
149
return pjmedia_clock_stop(m->clock);
153
/* Poll the master port clock */
154
PJ_DEF(pj_bool_t) pjmedia_master_port_wait( pjmedia_master_port *m,
158
PJ_ASSERT_RETURN(m && m->clock, PJ_FALSE);
160
return pjmedia_clock_wait(m->clock, wait, ts);
164
* Callback to be called for each clock ticks.
166
static void clock_callback(const pj_timestamp *ts, void *user_data)
168
pjmedia_master_port *m = (pjmedia_master_port*) user_data;
173
/* Lock access to ports. */
174
pj_lock_acquire(m->lock);
176
/* Get frame from upstream port and pass it to downstream port */
177
pj_bzero(&frame, sizeof(frame));
179
frame.size = m->buff_size;
180
frame.timestamp.u64 = ts->u64;
182
status = pjmedia_port_get_frame(m->u_port, &frame);
183
if (status != PJ_SUCCESS)
184
frame.type = PJMEDIA_FRAME_TYPE_NONE;
186
status = pjmedia_port_put_frame(m->d_port, &frame);
188
/* Get frame from downstream port and pass it to upstream port */
189
pj_bzero(&frame, sizeof(frame));
191
frame.size = m->buff_size;
192
frame.timestamp.u64 = ts->u64;
194
status = pjmedia_port_get_frame(m->d_port, &frame);
195
if (status != PJ_SUCCESS)
196
frame.type = PJMEDIA_FRAME_TYPE_NONE;
198
status = pjmedia_port_put_frame(m->u_port, &frame);
201
pj_lock_release(m->lock);
206
* Change the upstream port.
208
PJ_DEF(pj_status_t) pjmedia_master_port_set_uport(pjmedia_master_port *m,
211
PJ_ASSERT_RETURN(m && port, PJ_EINVAL);
213
/* Only supports audio for now */
214
PJ_ASSERT_RETURN(port->info.fmt.type==PJMEDIA_TYPE_AUDIO, PJ_ENOTSUP);
216
/* If we have downstream port, make sure they have matching samples per
221
PJMEDIA_PIA_PTIME(&port->info) ==
222
PJMEDIA_PIA_PTIME(&m->d_port->info),
223
PJMEDIA_ENCSAMPLESPFRAME
227
pj_lock_acquire(m->lock);
231
pj_lock_release(m->lock);
238
* Get the upstream port.
240
PJ_DEF(pjmedia_port*) pjmedia_master_port_get_uport(pjmedia_master_port*m)
242
PJ_ASSERT_RETURN(m, NULL);
248
* Change the downstream port.
250
PJ_DEF(pj_status_t) pjmedia_master_port_set_dport(pjmedia_master_port *m,
253
PJ_ASSERT_RETURN(m && port, PJ_EINVAL);
255
/* Only supports audio for now */
256
PJ_ASSERT_RETURN(port->info.fmt.type==PJMEDIA_TYPE_AUDIO, PJ_ENOTSUP);
258
/* If we have upstream port, make sure they have matching samples per
263
PJMEDIA_PIA_PTIME(&port->info) ==
264
PJMEDIA_PIA_PTIME(&m->u_port->info),
265
PJMEDIA_ENCSAMPLESPFRAME
269
pj_lock_acquire(m->lock);
273
pj_lock_release(m->lock);
280
* Get the downstream port.
282
PJ_DEF(pjmedia_port*) pjmedia_master_port_get_dport(pjmedia_master_port*m)
284
PJ_ASSERT_RETURN(m, NULL);
290
* Destroy the master port, and optionally destroy the u_port and
293
PJ_DEF(pj_status_t) pjmedia_master_port_destroy(pjmedia_master_port *m,
294
pj_bool_t destroy_ports)
296
PJ_ASSERT_RETURN(m, PJ_EINVAL);
299
pjmedia_clock_destroy(m->clock);
303
if (m->u_port && destroy_ports) {
304
pjmedia_port_destroy(m->u_port);
308
if (m->d_port && destroy_ports) {
309
pjmedia_port_destroy(m->d_port);
314
pj_lock_destroy(m->lock);