summaryrefslogtreecommitdiff
path: root/pjmedia/include/pjmedia/port.h
blob: 7c108ed9435e333b6d0f2162fa357fbae6fa5636 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
/* $Id$ */
/* 
 * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */
#ifndef __PJMEDIA_PORT_H__
#define __PJMEDIA_PORT_H__

/**
 * @file port.h
 * @brief Port interface declaration
 */
#include <pjmedia/types.h>
#include <pj/os.h>


/**
  @defgroup PJMEDIA_PORT_CONCEPT Media Ports Framework
  @ingroup PJMEDIA
  @brief Extensible framework for media terminations
  
  @section media_port_intro Media Port Concepts
  
  @subsection The Media Port
  A media port (represented with pjmedia_port "class") provides a generic
  and extensible framework for implementing media terminations. A media
  port interface basically has the following properties:
  - media port information (pjmedia_port_info) to describe the
  media port properties (sampling rate, number of channels, etc.),
  - pointer to function to acquire frames from the port (<tt>get_frame()
  </tt> interface), which will be called by #pjmedia_port_get_frame()
  public API, and
  - pointer to function to store frames to the port (<tt>put_frame()</tt>
  interface) which will be called by #pjmedia_port_put_frame() public
  API.
  
  Media ports are passive "objects". Applications (or other PJMEDIA 
  components) must actively calls #pjmedia_port_get_frame() or 
  #pjmedia_port_put_frame() from/to the media port in order to retrieve/
  store media frames.
  
  Some media ports (such as @ref PJMEDIA_CONF and @ref PJMEDIA_RESAMPLE_PORT)
  may be interconnected with each other, while some
  others represent the ultimate source/sink termination for the media. 


  @subsection port_clock_ex1 Example: Manual Resampling

  For example, suppose application wants to convert the sampling rate
  of one WAV file to another. In this case, application would create and
  arrange media ports connection as follows:

    \image html sample-manual-resampling.jpg

  Application would setup the media ports using the following pseudo-
  code:

  \code
  
      pjmedia_port *player, *resample, *writer;
      pj_status_t status;
  
      // Create the file player port.
      status = pjmedia_wav_player_port_create(pool, 
  					      "Input.WAV",	    // file name
  					      20,		    // ptime.
  					      PJMEDIA_FILE_NO_LOOP, // flags
  					      0,		    // buffer size
  					      NULL,		    // user data.
  					      &player );
      PJ_ASSERT_RETURN(status==PJ_SUCCESS, PJ_SUCCESS);
  
      // Create the resample port with specifying the target sampling rate, 
      // and with the file port as the source. This will effectively
      // connect the resample port with the player port.
      status = pjmedia_resample_port_create( pool, player, 8000, 
  					     0, &resample);
      PJ_ASSERT_RETURN(status==PJ_SUCCESS, PJ_SUCCESS);
  
      // Create the file writer, specifying the resample port's configuration
      // as the WAV parameters.
      status pjmedia_wav_writer_port_create(pool, 
  					    "Output.WAV",  // file name.
  					    resample->info.clock_rate,
  					    resample->info.channel_count,
  					    resample->info.samples_per_frame,
  					    resample->info.bits_per_sample,
  					    0,		// flags
  					    0,		// buffer size
  					    NULL,	// user data.
  					    &writer);
  
  \endcode

  
  After the ports have been set up, application can perform the conversion
  process by running this loop:
 
  \code
  
  	pj_int16_t samplebuf[MAX_FRAME];
  	
  	while (1) {
  	    pjmedia_frame frame;
  	    pj_status_t status;
  
  	    frame.buf = samplebuf;
  	    frame.size = sizeof(samplebuf);
  
  	    // Get the frame from resample port.
  	    status = pjmedia_port_get_frame(resample, &frame);
  	    if (status != PJ_SUCCESS || frame.type == PJMEDIA_FRAME_TYPE_NONE) {
  		// End-of-file, end the conversion.
  		break;
  	    }
  
  	    // Put the frame to write port.
  	    status = pjmedia_port_put_frame(writer, &frame);
  	    if (status != PJ_SUCCESS) {
  		// Error in writing the file.
  		break;
  	    }
  	}
  
  \endcode
 
  For the sake of completeness, after the resampling process is done, 
  application would need to destroy the ports:
  
  \code
	// Note: by default, destroying resample port will destroy the
	//	 the downstream port too.
  	pjmedia_port_destroy(resample);
  	pjmedia_port_destroy(writer);
  \endcode
 
 
  The above steps are okay for our simple purpose of changing file's sampling
  rate. But for other purposes, the process of reading and writing frames
  need to be done in timely manner (for example, sending RTP packets to
  remote stream). And more over, as the application's scope goes bigger,
  the same pattern of manually reading/writing frames comes up more and more often,
  thus perhaps it would be better if PJMEDIA provides mechanism to 
  automate this process.
  
  And indeed PJMEDIA does provide such mechanism, which is described in 
  @ref PJMEDIA_PORT_CLOCK section.


  @subsection media_port_autom Automating Media Flow

  PJMEDIA provides few mechanisms to make media flows automatically
  among media ports. This concept is described in @ref PJMEDIA_PORT_CLOCK 
  section.

 */


/**
 * @defgroup PJMEDIA_PORT_INTERFACE Media Port Interface
 * @ingroup PJMEDIA_PORT_CONCEPT
 * @brief Declares the media port interface.
 */

/**
 * @defgroup PJMEDIA_PORT Ports
 * @ingroup PJMEDIA_PORT_CONCEPT
 * @brief Contains various types of media ports/terminations.
 * @{
 * This page lists all types of media ports currently implemented
 * in PJMEDIA. The media port concept is explained in @ref PJMEDIA_PORT_CONCEPT.
 * @}
 */

/**
 @defgroup PJMEDIA_PORT_CLOCK Clock/Timing
 @ingroup PJMEDIA_PORT_CONCEPT
 @brief Various types of classes that provide timing.
 @{

 The media clock/timing extends the media port concept that is explained 
 in @ref PJMEDIA_PORT_CONCEPT. When clock is present in the ports 
 interconnection, media will flow automatically (and with correct timing too!)
 from one media port to another.
 
 There are few objects in PJMEDIA that are able to provide clock/timing
 to media ports interconnection:

 - @ref PJMED_SND_PORT\n
   The sound device makes a good candidate as the clock source, and
   PJMEDIA @ref PJMED_SND is designed so that it is able to invoke
   operations according to timing driven by the sound hardware clock
   (this may sound complicated, but actually it just means that
   the sound device abstraction provides callbacks to be called when
   it has/wants media frames).\n
   See @ref PJMED_SND_PORT for more details.

 - @ref PJMEDIA_MASTER_PORT\n
   The master port uses @ref PJMEDIA_CLOCK as the clock source. By using
   @ref PJMEDIA_MASTER_PORT, it is possible to interconnect passive
   media ports and let the frames flow automatically in timely manner.\n
   Please see @ref PJMEDIA_MASTER_PORT for more details.

 @}
 */

/**
 * @addtogroup PJMEDIA_PORT_INTERFACE
 * @{
 * This page contains the media port interface declarations. The media port
 * concept is explained in @ref PJMEDIA_PORT_CONCEPT.
 */

PJ_BEGIN_DECL


/**
 * Port operation setting.
 */
enum pjmedia_port_op
{
    /** 
     * No change to the port TX or RX settings.
     */
    PJMEDIA_PORT_NO_CHANGE,

    /**
     * TX or RX is disabled from the port. It means get_frame() or
     * put_frame() WILL NOT be called for this port.
     */
    PJMEDIA_PORT_DISABLE,

    /**
     * TX or RX is muted, which means that get_frame() or put_frame()
     * will still be called, but the audio frame is discarded.
     */
    PJMEDIA_PORT_MUTE,

    /**
     * Enable TX and RX to/from this port.
     */
    PJMEDIA_PORT_ENABLE
};


/**
 * @see pjmedia_port_op
 */
typedef enum pjmedia_port_op pjmedia_port_op;


/**
 * Port info.
 */
typedef struct pjmedia_port_info
{
    pj_str_t	    name;		/**< Port name.			    */
    pj_uint32_t	    signature;		/**< Port signature.		    */
    pjmedia_type    type;		/**< Media type.		    */
    pj_bool_t	    has_info;		/**< Has info?			    */
    pj_bool_t	    need_info;		/**< Need info on connect?	    */
    unsigned	    pt;			/**< Payload type (can be dynamic). */
    pj_str_t	    encoding_name;	/**< Encoding name.		    */
    unsigned	    clock_rate;		/**< Sampling rate.		    */
    unsigned	    channel_count;	/**< Number of channels.	    */
    unsigned	    bits_per_sample;	/**< Bits/sample		    */
    unsigned	    samples_per_frame;	/**< No of samples per frame.	    */
    unsigned	    bytes_per_frame;	/**< No of samples per frame.	    */
} pjmedia_port_info;


/** 
 * Types of media frame. 
 */
typedef enum pjmedia_frame_type
{
    PJMEDIA_FRAME_TYPE_NONE,	    /**< No frame.		*/
    PJMEDIA_FRAME_TYPE_AUDIO	    /**< Normal audio frame.	*/

} pjmedia_frame_type;


/** 
 * This structure describes a media frame. 
 */
struct pjmedia_frame
{
    pjmedia_frame_type	 type;	    /**< Frame type.		    */
    void		*buf;	    /**< Pointer to buffer.	    */
    pj_size_t		 size;	    /**< Frame size in bytes.	    */
    pj_timestamp	 timestamp; /**< Frame timestamp.	    */
};


/** 
 * @see pjmedia_frame
 */
typedef struct pjmedia_frame pjmedia_frame;


/**
 * For future graph.
 */
typedef struct pjmedia_graph pjmedia_graph;


/**
 * @see pjmedia_port
 */
typedef struct pjmedia_port pjmedia_port;

/**
 * Port interface.
 */
struct pjmedia_port
{
    pjmedia_port_info	 info;		    /**< Port information.  */

    /** Port data can be used by the port creator to attach arbitrary
     *  value to be associated with the port.
     */
    struct port_data {
	void		*pdata;		    /**< Pointer data.	    */
	long		 ldata;		    /**< Long data.	    */
    } port_data;

    /**
     * Sink interface. 
     * This should only be called by #pjmedia_port_put_frame().
     */
    pj_status_t (*put_frame)(pjmedia_port *this_port, 
			     const pjmedia_frame *frame);

    /**
     * Source interface. 
     * This should only be called by #pjmedia_port_get_frame().
     */
    pj_status_t (*get_frame)(pjmedia_port *this_port, 
			     pjmedia_frame *frame);

    /**
     * Called to destroy this port.
     */
    pj_status_t (*on_destroy)(pjmedia_port *this_port);
};


/**
 * This is an auxiliary function to initialize port info for
 * ports which deal with PCM audio.
 *
 * @param info		    The port info to be initialized.
 * @param name		    Port name.
 * @param signature	    Port signature.
 * @param clock_rate	    Port's clock rate.
 * @param channel_count	    Number of channels.
 * @param bits_per_sample   Bits per sample.
 * @param samples_per_frame Number of samples per frame.
 *
 * @return		    PJ_SUCCESS on success.
 */
PJ_DECL(pj_status_t) pjmedia_port_info_init( pjmedia_port_info *info,
					     const pj_str_t *name,
					     unsigned signature,
					     unsigned clock_rate,
					     unsigned channel_count,
					     unsigned bits_per_sample,
					     unsigned samples_per_frame);


/**
 * Get a frame from the port (and subsequent downstream ports).
 *
 * @param port	    The media port.
 * @param frame	    Frame to store samples.
 *
 * @return	    PJ_SUCCESS on success, or the appropriate error code.
 */
PJ_DECL(pj_status_t) pjmedia_port_get_frame( pjmedia_port *port,
					     pjmedia_frame *frame );

/**
 * Put a frame to the port (and subsequent downstream ports).
 *
 * @param port	    The media port.
 * @param frame	    Frame to the put to the port.
 *
 * @return	    PJ_SUCCESS on success, or the appropriate error code.
 */
PJ_DECL(pj_status_t) pjmedia_port_put_frame( pjmedia_port *port,
					     const pjmedia_frame *frame );


/**
 * Destroy port (and subsequent downstream ports)
 *
 * @param port	    The media port.
 *
 * @return	    PJ_SUCCESS on success, or the appropriate error code.
 */
PJ_DECL(pj_status_t) pjmedia_port_destroy( pjmedia_port *port );



PJ_END_DECL

/**
 * @}
 */

#endif	/* __PJMEDIA_PORT_H__ */