Ticket #504: ticket504.4.patch

File ticket504.4.patch, 37.9 KB (added by nanang, 16 years ago)

Fix issue number 4 to 6

  • pjsip/include/pjsua-lib/pjsua.h

    C:\project\pjproject-trunk>svn diff pjsip\include\pjsua-lib\pjsua.h pjsip\src\pjsua-lib\pjsua_media.c pjsip\src\pjsua-lib\pjsua_core.c pjsip-apps\src\pjsua\pjsua_app.c pjmedia\src\pjmedia\conference.c pjmedia\include\pjmedia\stereo.h pjmedia\src\pjmedia\stereo_port.c pjmedia\build\pjmedia.dsp pjmedia\build\pjmedia.vcproj pjsip-apps\src\samples\stereotest.c pjmedia\include\pjmedia.h 
     
    37493749    unsigned            snd_clock_rate; 
    37503750 
    37513751    /** 
     3752     * Channel count be applied when opening the sound device and 
     3753     * conference bridge. 
     3754     */ 
     3755    unsigned            channel_count; 
     3756 
     3757    /** 
    37523758     * Specify audio frame ptime. The value here will affect the  
    37533759     * samples per frame of both the sound device and the conference 
    37543760     * bridge. Specifying lower ptime will normally reduce the 
  • pjsip/src/pjsua-lib/pjsua_media.c

     
    169169    /* Save additional conference bridge parameters for future 
    170170     * reference. 
    171171     */ 
    172     pjsua_var.mconf_cfg.channel_count = 1; 
     172    pjsua_var.mconf_cfg.channel_count = pjsua_var.media_cfg.channel_count; 
    173173    pjsua_var.mconf_cfg.bits_per_sample = 16; 
    174174    pjsua_var.mconf_cfg.samples_per_frame = pjsua_var.media_cfg.clock_rate *  
    175175                                            pjsua_var.mconf_cfg.channel_count * 
     
    18341834        fps = 1000 / pjsua_var.media_cfg.audio_frame_ptime; 
    18351835        status = pjmedia_snd_port_create(pjsua_var.pool, capture_dev, 
    18361836                                         playback_dev,  
    1837                                          clock_rates[i], 1, 
    1838                                          clock_rates[i]/fps, 
     1837                                         clock_rates[i],  
     1838                                         pjsua_var.media_cfg.channel_count, 
     1839                                         clock_rates[i]/fps *  
     1840                                         pjsua_var.media_cfg.channel_count, 
    18391841                                         16, 0, &pjsua_var.snd_port); 
    18401842 
    18411843        if (status == PJ_SUCCESS) { 
  • pjsip/src/pjsua-lib/pjsua_core.c

     
    163163 
    164164    cfg->clock_rate = PJSUA_DEFAULT_CLOCK_RATE; 
    165165    cfg->snd_clock_rate = 0; 
     166    cfg->channel_count = 1; 
    166167    cfg->audio_frame_ptime = PJSUA_DEFAULT_AUDIO_FRAME_PTIME; 
    167168    cfg->max_media_ports = PJSUA_MAX_CONF_PORTS; 
    168169    cfg->has_ioqueue = PJ_TRUE; 
  • pjsip-apps/src/pjsua/pjsua_app.c

     
    175175    puts  ("  --dis-codec=name    Disable codec (can be specified multiple times)"); 
    176176    puts  ("  --clock-rate=N      Override conference bridge clock rate"); 
    177177    puts  ("  --snd-clock-rate=N  Override sound device clock rate"); 
     178    puts  ("  --stereo            Audio device and conference bridge opened in stereo mode"); 
    178179    puts  ("  --null-audio        Use NULL audio device"); 
    179180    puts  ("  --play-file=file    Register WAV file in conference bridge."); 
    180181    puts  ("                      This can be specified multiple times."); 
     
    389390           OPT_NAMESERVER, OPT_STUN_DOMAIN, OPT_STUN_SRV, 
    390391           OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE, 
    391392           OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP, 
    392            OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_SND_CLOCK_RATE, OPT_USE_ICE, 
    393            OPT_USE_SRTP, OPT_SRTP_SECURE, 
     393           OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_SND_CLOCK_RATE, OPT_STEREO, 
     394           OPT_USE_ICE, OPT_USE_SRTP, OPT_SRTP_SECURE, 
    394395           OPT_PLAY_FILE, OPT_PLAY_TONE, OPT_RTP_PORT, OPT_ADD_CODEC,  
    395396           OPT_ILBC_MODE, OPT_REC_FILE, OPT_AUTO_REC, 
    396397           OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME, OPT_NO_VAD, 
     
    413414        { "version",    0, 0, OPT_VERSION}, 
    414415        { "clock-rate", 1, 0, OPT_CLOCK_RATE}, 
    415416        { "snd-clock-rate",     1, 0, OPT_SND_CLOCK_RATE}, 
     417        { "stereo",     0, 0, OPT_STEREO}, 
    416418        { "null-audio", 0, 0, OPT_NULL_AUDIO}, 
    417419        { "local-port", 1, 0, OPT_LOCAL_PORT}, 
    418420        { "ip-addr",    1, 0, OPT_IP_ADDR}, 
     
    582584            cfg->media_cfg.snd_clock_rate = lval;  
    583585            break; 
    584586 
     587        case OPT_STEREO: 
     588            cfg->media_cfg.channel_count = 2; 
     589            break; 
     590 
    585591        case OPT_LOCAL_PORT:   /* local-port */ 
    586592            lval = pj_strtoul(pj_cstr(&tmp, pj_optarg)); 
    587593            if (lval < 0 || lval > 65535) { 
     
    14121418        pj_strcat2(&cfg, line); 
    14131419    } 
    14141420 
     1421    /* Stereo mode. */ 
     1422    if (config->media_cfg.channel_count == 2) { 
     1423        pj_ansi_sprintf(line, "--stereo\n"); 
     1424        pj_strcat2(&cfg, line); 
     1425    } 
     1426 
    14151427    /* quality */ 
    14161428    if (config->media_cfg.quality != PJSUA_DEFAULT_CODEC_QUALITY) { 
    14171429        pj_ansi_sprintf(line, "--quality %d\n", 
  • pjmedia/src/pjmedia/conference.c

     
    2424#include <pjmedia/resample.h> 
    2525#include <pjmedia/silencedet.h> 
    2626#include <pjmedia/sound_port.h> 
     27#include <pjmedia/stereo.h> 
    2728#include <pjmedia/stream.h> 
    2829#include <pj/array.h> 
    2930#include <pj/assert.h> 
     
    117118    /* Shortcut for port info. */ 
    118119    unsigned             clock_rate;    /**< Port's clock rate.             */ 
    119120    unsigned             samples_per_frame; /**< Port's samples per frame.  */ 
     121    unsigned             channel_count; /**< Port's channel count.          */ 
    120122 
    121123    /* Calculated signal levels: */ 
    122124    unsigned             tx_level;      /**< Last tx level to this port.    */ 
     
    285287        conf_port->port = port; 
    286288        conf_port->clock_rate = port->info.clock_rate; 
    287289        conf_port->samples_per_frame = port->info.samples_per_frame; 
     290        conf_port->channel_count = port->info.channel_count; 
    288291    } else { 
    289292        conf_port->port = NULL; 
    290293        conf_port->clock_rate = conf->clock_rate; 
    291294        conf_port->samples_per_frame = conf->samples_per_frame; 
     295        conf_port->channel_count = conf->channel_count; 
    292296    } 
    293297 
    294298    /* Create and init vad. */ 
     
    349353     * port's clock rate is different then the conference bridge settings. 
    350354     */ 
    351355    if (conf_port->clock_rate != conf->clock_rate || 
     356        conf_port->channel_count != conf->channel_count || 
    352357        conf_port->samples_per_frame != conf->samples_per_frame) 
    353358    { 
     359        unsigned port_ptime, conf_ptime, buff_ptime; 
     360 
     361        port_ptime = conf_port->samples_per_frame / conf_port->channel_count * 
     362            1000 / conf_port->clock_rate; 
     363        conf_ptime = conf->samples_per_frame / conf->channel_count * 
     364            1000 / conf->clock_rate; 
     365 
     366        /* Calculate ptime to be applied to the port buffer */ 
     367        if (port_ptime > conf_ptime) { 
     368            buff_ptime = conf_ptime * (port_ptime / conf_ptime); 
     369            if (port_ptime % conf_ptime) 
     370                buff_ptime += conf_ptime; 
     371        } else { 
     372            buff_ptime = port_ptime * (conf_ptime / port_ptime); 
     373            if (conf_ptime % port_ptime) 
     374                buff_ptime += port_ptime; 
     375        } 
     376 
    354377        /* Create RX buffer. */ 
    355         conf_port->rx_buf_cap = (unsigned)(conf_port->samples_per_frame + 
    356                                            conf->samples_per_frame *  
    357                                            conf_port->clock_rate * 1.0 / 
    358                                            conf->clock_rate); 
     378        //conf_port->rx_buf_cap = (unsigned)(conf_port->samples_per_frame + 
     379        //                                 conf->samples_per_frame *  
     380        //                                 conf_port->clock_rate * 1.0 / 
     381        //                                 conf->clock_rate); 
     382        conf_port->rx_buf_cap = conf_port->clock_rate * buff_ptime / 1000; 
     383        if (conf_port->channel_count > conf->channel_count) 
     384            conf_port->rx_buf_cap *= conf_port->channel_count; 
     385        else 
     386            conf_port->rx_buf_cap *= conf->channel_count; 
     387 
    359388        conf_port->rx_buf_count = 0; 
    360389        conf_port->rx_buf = (pj_int16_t*) 
    361390                            pj_pool_alloc(pool, conf_port->rx_buf_cap * 
     
    698727    if (!port_name) 
    699728        port_name = &strm_port->info.name; 
    700729 
    701     /* For this version of PJMEDIA, port MUST have the same number of 
    702      * PCM channels. 
     730    /* For this version of PJMEDIA, channel(s) number MUST be: 
     731     * - same between port & conference bridge. 
     732     * - monochannel on port or conference bridge. 
    703733     */ 
    704     if (strm_port->info.channel_count != conf->channel_count) { 
     734    if (strm_port->info.channel_count != conf->channel_count &&  
     735        (strm_port->info.channel_count != 1 && conf->channel_count != 1))  
     736    { 
    705737        pj_assert(!"Number of channels mismatch"); 
    706738        return PJMEDIA_ENCCHANNEL; 
    707739    } 
     
    766798 
    767799    PJ_ASSERT_RETURN(conf && pool, PJ_EINVAL); 
    768800 
    769     /* For this version of PJMEDIA, port MUST have the same number of 
    770      * PCM channels. 
     801    /* For this version of PJMEDIA, channel(s) number MUST be: 
     802     * - same between port & conference bridge. 
     803     * - monochannel on port or conference bridge. 
    771804     */ 
    772     if (channel_count != conf->channel_count) { 
     805    if (channel_count != conf->channel_count &&  
     806        (channel_count != 1 && conf->channel_count != 1))  
     807    { 
    773808        pj_assert(!"Number of channels mismatch"); 
    774809        return PJMEDIA_ENCCHANNEL; 
    775810    } 
     
    12741309                       (int)cport->name.slen, cport->name.ptr, 
    12751310                       count)); 
    12761311 
    1277     /* If port's samples per frame and sampling rate matches conference 
     1312    /*  
     1313     * If port's samples per frame and sampling rate matches conference 
    12781314     * bridge's settings, get the frame directly from the port. 
    12791315     */ 
    12801316    if (cport->rx_buf_cap == 0) { 
     
    12951331        return status; 
    12961332 
    12971333    } else { 
     1334        unsigned samples_req; 
    12981335 
    12991336        /* Initialize frame type */ 
    13001337        if (cport->rx_buf_count == 0) { 
     
    13061343 
    13071344        /* 
    13081345         * If we don't have enough samples in rx_buf, read from the port  
    1309          * first. Remember that rx_buf may be in different clock rate! 
     1346         * first. Remember that rx_buf may be in different clock rate and 
     1347         * channel count! 
    13101348         */ 
    1311         while (cport->rx_buf_count < count * 1.0 * 
    1312                 cport->clock_rate / conf->clock_rate) { 
    13131349 
     1350        samples_req = (unsigned) (count * 1.0 *  
     1351                      cport->clock_rate / conf->clock_rate); 
     1352 
     1353        while (cport->rx_buf_count < samples_req) { 
     1354 
    13141355            pjmedia_frame f; 
    13151356            pj_status_t status; 
    13161357 
     
    13361377                *type = PJMEDIA_FRAME_TYPE_AUDIO; 
    13371378            } 
    13381379 
    1339             cport->rx_buf_count += cport->samples_per_frame; 
     1380            /* Adjust channels */ 
     1381            if (cport->channel_count != conf->channel_count) { 
     1382                if (cport->channel_count == 1) { 
     1383                    pjmedia_stereo_convert_from_mono(f.buf, f.buf, 
     1384                                                     conf->channel_count,  
     1385                                                     cport->samples_per_frame, 
     1386                                                     0); 
     1387                    cport->rx_buf_count += (cport->samples_per_frame *  
     1388                                            conf->channel_count); 
     1389                } else { /* conf->channel_count == 1 */ 
     1390                    pjmedia_stereo_convert_to_mono(f.buf, f.buf, 
     1391                                                   cport->channel_count,  
     1392                                                   cport->samples_per_frame/ 
     1393                                                   cport->channel_count, 
     1394                                                   0); 
     1395                    cport->rx_buf_count += (cport->samples_per_frame /  
     1396                                            cport->channel_count); 
     1397                } 
     1398            } else { 
     1399                cport->rx_buf_count += cport->samples_per_frame; 
     1400            } 
    13401401 
    13411402            TRACE_((THIS_FILE, "  rx buffer size is now %d", 
    13421403                    cport->rx_buf_count)); 
     
    13611422                                   conf->clock_rate); 
    13621423            cport->rx_buf_count -= src_count; 
    13631424            if (cport->rx_buf_count) { 
    1364                 pjmedia_copy_samples(cport->rx_buf, cport->rx_buf+src_count, 
     1425                pjmedia_move_samples(cport->rx_buf, cport->rx_buf+src_count, 
    13651426                                     cport->rx_buf_count); 
    13661427            } 
    13671428 
     
    13731434            pjmedia_copy_samples(frame, cport->rx_buf, count); 
    13741435            cport->rx_buf_count -= count; 
    13751436            if (cport->rx_buf_count) { 
    1376                 pjmedia_copy_samples(cport->rx_buf, cport->rx_buf+count, 
     1437                pjmedia_move_samples(cport->rx_buf, cport->rx_buf+count, 
    13771438                                     cport->rx_buf_count); 
    13781439            } 
    13791440        } 
     
    13951456    pj_status_t status; 
    13961457    pj_int32_t adj_level; 
    13971458    pj_int32_t tx_level; 
     1459    unsigned dst_count; 
    13981460 
    13991461    *frm_type = PJMEDIA_FRAME_TYPE_AUDIO; 
    14001462 
     
    14121474 
    14131475        /* Add sample counts to heart-beat samples */ 
    14141476        cport->tx_heart_beat += conf->samples_per_frame * cport->clock_rate / 
    1415                                 conf->clock_rate; 
     1477                                conf->clock_rate *  
     1478                                cport->channel_count / conf->channel_count; 
    14161479 
    14171480        /* Set frame timestamp */ 
    14181481        frame.timestamp.u64 = timestamp->u64 * cport->clock_rate / 
     
    15081571     * the conference bridge, transmit the frame as is. 
    15091572     */ 
    15101573    if (cport->clock_rate == conf->clock_rate && 
    1511         cport->samples_per_frame == conf->samples_per_frame) 
     1574        cport->samples_per_frame == conf->samples_per_frame && 
     1575        cport->channel_count == conf->channel_count) 
    15121576    { 
    15131577        if (cport->port != NULL) { 
    15141578            pjmedia_frame frame; 
     
    15321596 
    15331597    /* If it has different clock_rate, must resample. */ 
    15341598    if (cport->clock_rate != conf->clock_rate) { 
    1535  
    1536         unsigned dst_count; 
    1537  
    15381599        pjmedia_resample_run( cport->tx_resample, buf,  
    15391600                              cport->tx_buf + cport->tx_buf_count ); 
    1540  
    15411601        dst_count = (unsigned)(conf->samples_per_frame * 1.0 * 
    15421602                               cport->clock_rate / conf->clock_rate); 
    1543         cport->tx_buf_count += dst_count; 
    1544  
    15451603    } else { 
    15461604        /* Same clock rate. 
    15471605         * Just copy the samples to tx_buffer. 
    15481606         */ 
    15491607        pjmedia_copy_samples( cport->tx_buf + cport->tx_buf_count, 
    15501608                              buf, conf->samples_per_frame ); 
    1551         cport->tx_buf_count += conf->samples_per_frame; 
     1609        dst_count = conf->samples_per_frame; 
    15521610    } 
    15531611 
     1612    /* Adjust channels */ 
     1613    if (cport->channel_count != conf->channel_count) { 
     1614        pj_int16_t *tx_buf = cport->tx_buf + cport->tx_buf_count; 
     1615        if (conf->channel_count == 1) { 
     1616            pjmedia_stereo_convert_from_mono(tx_buf, tx_buf, 
     1617                                             cport->channel_count,  
     1618                                             dst_count, 0); 
     1619            dst_count *= cport->channel_count; 
     1620        } else { /* cport->channel_count == 1 */ 
     1621            pjmedia_stereo_convert_to_mono(tx_buf, tx_buf, 
     1622                                           conf->channel_count,  
     1623                                           dst_count/ 
     1624                                           conf->channel_count, 
     1625                                           0); 
     1626            dst_count /= conf->channel_count; 
     1627        } 
     1628    } 
     1629 
     1630    cport->tx_buf_count += dst_count; 
     1631 
     1632    pj_assert(cport->tx_buf_count <= cport->tx_buf_cap); 
     1633 
    15541634    /* Transmit while we have enough frame in the tx_buf. */ 
    15551635    status = PJ_SUCCESS; 
    15561636    ts = 0; 
     
    15891669 
    15901670        cport->tx_buf_count -= cport->samples_per_frame; 
    15911671        if (cport->tx_buf_count) { 
    1592             pjmedia_copy_samples(cport->tx_buf,  
     1672            pjmedia_move_samples(cport->tx_buf,  
    15931673                                 cport->tx_buf + cport->samples_per_frame, 
    15941674                                 cport->tx_buf_count); 
    15951675        } 
  • pjmedia/include/pjmedia/stereo.h

     
     1/* $Id$ */ 
     2/*  
     3 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> 
     4 * 
     5 * This program is free software; you can redistribute it and/or modify 
     6 * it under the terms of the GNU General Public License as published by 
     7 * the Free Software Foundation; either version 2 of the License, or 
     8 * (at your option) any later version. 
     9 * 
     10 * This program is distributed in the hope that it will be useful, 
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     13 * GNU General Public License for more details. 
     14 * 
     15 * You should have received a copy of the GNU General Public License 
     16 * along with this program; if not, write to the Free Software 
     17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
     18 */ 
     19#ifndef __PJMEDIA_STEREO_H__ 
     20#define __PJMEDIA_STEREO_H__ 
     21 
     22/** 
     23 * @file stereo.h 
     24 * @brief Monochannel and multichannel converter. 
     25 */ 
     26 
     27#include <pjmedia/errno.h> 
     28#include <pjmedia/port.h> 
     29#include <pjmedia/types.h> 
     30#include <pj/assert.h> 
     31 
     32 
     33/** 
     34 * @defgroup PJMEDIA_STEREO Monochannel and multichannel audio frame converter 
     35 * @ingroup PJMEDIA_MISC 
     36 * @brief Interface for converting monochannel audio frame to multichannel 
     37 * audio frame and vice versa. 
     38 * @{ 
     39 * 
     40 */ 
     41 
     42PJ_BEGIN_DECL 
     43 
     44 
     45/**  
     46 * Options for channel converter. 
     47 */ 
     48enum pjmedia_stereo_options 
     49{ 
     50    /** 
     51     * Multichannel to monochannel conversion just takes audio samples from  
     52     * the first channel. 
     53     */ 
     54    PJMEDIA_STEREO_SIMPLE   = 0, 
     55 
     56    /** 
     57     * Multichannel to monochannel conversion mixes samples from all channels 
     58     * into the monochannel. 
     59     */ 
     60    PJMEDIA_STEREO_MIX      = 1 
     61}; 
     62 
     63 
     64/** 
     65 * Multichannel to monochannel conversion, it has two operation mode specified 
     66 * by param options, @see pjmedia_stereo_options. This function can work safely 
     67 * using the same buffer (in place conversion). 
     68 * 
     69 * @param mono              Monochannel audio frame. 
     70 * @param multi             Multichannel audio frame. 
     71 * @param channel_count     Number of channel. 
     72 * @param nsamples          Number of samples of monochannel. 
     73 * @param options           Options for conversion, @see pjmedia_stereo_options. 
     74 * 
     75 * @return                  PJ_SUCCESS on success; 
     76 */ 
     77PJ_INLINE(pj_status_t) pjmedia_stereo_convert_to_mono(pj_int16_t mono[], 
     78                                                      const pj_int16_t multi[], 
     79                                                      unsigned channel_count, 
     80                                                      unsigned nsamples, 
     81                                                      unsigned options) 
     82{ 
     83    unsigned i; 
     84 
     85    PJ_ASSERT_RETURN(mono && multi && channel_count && nsamples, PJ_EINVAL); 
     86 
     87    if ((options & PJMEDIA_STEREO_MIX) == 0) { 
     88        for (i = 0; i < nsamples; ++i) 
     89            mono[i] = multi[i * channel_count]; 
     90    } else { 
     91        unsigned j; 
     92        int tmp; 
     93        for (i = 0; i < nsamples; ++i) { 
     94            tmp = 0; 
     95            for(j = 0; j < channel_count; ++j) 
     96                tmp += multi[i * channel_count + j]; 
     97 
     98            if (tmp > 32767) tmp = 32767; 
     99            else if (tmp < -32768) tmp = -32768; 
     100            mono[i] = (pj_int16_t) tmp; 
     101        } 
     102    } 
     103 
     104    return PJ_SUCCESS; 
     105} 
     106 
     107 
     108/** 
     109 * Monochannel to multichannel conversion, it will just duplicate the samples 
     110 * from monochannel frame to all channels in the multichannel frame.  
     111 * This function can work safely using the same buffer (in place conversion) 
     112 * as long as the buffer is big enough for the multichannel samples. 
     113 * 
     114 * @param multi             Multichannel audio frame. 
     115 * @param mono              Monochannel audio frame. 
     116 * @param channel_count     Number of channel. 
     117 * @param nsamples          Number of samples of monochannel. 
     118 * @param options           Options for conversion, currently must be zero. 
     119 * 
     120 * @return                  PJ_SUCCESS on success; 
     121 */ 
     122PJ_INLINE(pj_status_t) pjmedia_stereo_convert_from_mono(pj_int16_t multi[], 
     123                                                        const pj_int16_t mono[], 
     124                                                        unsigned channel_count, 
     125                                                        unsigned nsamples, 
     126                                                        unsigned options) 
     127{ 
     128    int i; 
     129 
     130    PJ_ASSERT_RETURN(mono && multi && channel_count && nsamples, PJ_EINVAL); 
     131    PJ_ASSERT_RETURN(options == 0, PJ_EINVAL); 
     132 
     133    PJ_UNUSED_ARG(options); 
     134 
     135    while (nsamples--) { 
     136        for(i = channel_count-1; i >= 0; --i) 
     137            multi[nsamples * channel_count + i] = mono[nsamples]; 
     138    } 
     139 
     140    return PJ_SUCCESS; 
     141} 
     142 
     143 
     144/**  
     145 * Options for channel converter port. The @pjmedia_stereo_options is also 
     146 * valid for this port options. 
     147 */ 
     148enum pjmedia_stereo_port_options 
     149{ 
     150    /** 
     151     * Specifies whether this port should not destroy downstream port when  
     152     * this port is destroyed. 
     153     */ 
     154    PJMEDIA_STEREO_DONT_DESTROY_DN  = 4 
     155}; 
     156 
     157 
     158/** 
     159 * Create a mono-multi channel converter port. This creates a converter session, 
     160 * which will adjust the samples of audio frame to a different channel count 
     161 * when the port's get_frame() and put_frame() is called. 
     162 * 
     163 * When the port's get_frame() is called, this port will get a frame from  
     164 * the downstream port and convert the frame to the target channel count before 
     165 * returning it to the caller. 
     166 * 
     167 * When the port's put_frame() is called, this port will convert the frame 
     168 * to the downstream port's channel count before giving the frame to the  
     169 * downstream port. 
     170 * 
     171 * @param pool                  Pool to allocate the structure and buffers. 
     172 * @param dn_port               The downstream port, which channel count is to 
     173 *                              be converted to the target channel count. 
     174 * @param channel_count         This port channel count. 
     175 * @param options               Flags from #pjmedia_stereo_port_options. 
     176 *                              When this flag is zero, the default behavior 
     177 *                              is to use simple N-to-1 channel converter and  
     178 *                              to destroy downstream port when this port is  
     179 *                              destroyed. 
     180 * @param p_port                Pointer to receive the stereo port instance. 
     181 * 
     182 * @return PJ_SUCCESS on success. 
     183 */ 
     184PJ_DECL(pj_status_t) pjmedia_stereo_port_create( pj_pool_t *pool, 
     185                                                 pjmedia_port *dn_port, 
     186                                                 unsigned channel_count, 
     187                                                 unsigned options, 
     188                                                 pjmedia_port **p_port ); 
     189 
     190PJ_END_DECL 
     191 
     192/** 
     193 * @} 
     194 */ 
     195 
     196 
     197#endif  /* __PJMEDIA_STEREO_H__ */ 
     198 
  • pjmedia/src/pjmedia/stereo_port.c

     
     1/* $Id$ */ 
     2/*  
     3 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> 
     4 * 
     5 * This program is free software; you can redistribute it and/or modify 
     6 * it under the terms of the GNU General Public License as published by 
     7 * the Free Software Foundation; either version 2 of the License, or 
     8 * (at your option) any later version. 
     9 * 
     10 * This program is distributed in the hope that it will be useful, 
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     13 * GNU General Public License for more details. 
     14 * 
     15 * You should have received a copy of the GNU General Public License 
     16 * along with this program; if not, write to the Free Software 
     17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
     18 */ 
     19 
     20#include <pjmedia/stereo.h> 
     21#include <pj/assert.h> 
     22#include <pj/pool.h> 
     23#include <pj/string.h> 
     24 
     25 
     26#define SIGNATURE               PJMEDIA_PORT_SIGNATURE('S','T','R','O') 
     27 
     28 
     29struct stereo_port 
     30{ 
     31    pjmedia_port         base; 
     32    pjmedia_port        *dn_port; 
     33    unsigned             options; 
     34    pj_int16_t          *put_buf; 
     35    pj_int16_t          *get_buf; 
     36}; 
     37 
     38 
     39 
     40static pj_status_t stereo_put_frame(pjmedia_port *this_port, 
     41                                    const pjmedia_frame *frame); 
     42static pj_status_t stereo_get_frame(pjmedia_port *this_port,  
     43                                    pjmedia_frame *frame); 
     44static pj_status_t stereo_destroy(pjmedia_port *this_port); 
     45 
     46 
     47 
     48PJ_DEF(pj_status_t) pjmedia_stereo_port_create( pj_pool_t *pool, 
     49                                                pjmedia_port *dn_port, 
     50                                                unsigned channel_count, 
     51                                                unsigned options, 
     52                                                pjmedia_port **p_port ) 
     53{ 
     54    const pj_str_t name = pj_str("stereo"); 
     55    struct stereo_port *sport; 
     56    unsigned samples_per_frame; 
     57 
     58    /* Validate arguments. */ 
     59    PJ_ASSERT_RETURN(pool && dn_port && channel_count && p_port, PJ_EINVAL); 
     60 
     61    /* Only supports 16bit samples per frame */ 
     62    PJ_ASSERT_RETURN(dn_port->info.bits_per_sample == 16, PJMEDIA_ENCBITS); 
     63 
     64    /* Validate channel counts */ 
     65    PJ_ASSERT_RETURN(((dn_port->info.channel_count>1 && channel_count==1) || 
     66                      (dn_port->info.channel_count==1 && channel_count>1)), 
     67                      PJ_EINVAL); 
     68 
     69    /* Create and initialize port. */ 
     70    sport = PJ_POOL_ZALLOC_T(pool, struct stereo_port); 
     71    PJ_ASSERT_RETURN(sport != NULL, PJ_ENOMEM); 
     72 
     73    samples_per_frame = dn_port->info.samples_per_frame * channel_count / 
     74                        dn_port->info.channel_count; 
     75 
     76    pjmedia_port_info_init(&sport->base.info, &name, SIGNATURE,  
     77                           dn_port->info.clock_rate, 
     78                           channel_count,  
     79                           dn_port->info.bits_per_sample,  
     80                           samples_per_frame); 
     81 
     82    sport->dn_port = dn_port; 
     83    sport->options = options; 
     84 
     85    /* We always need buffer for put_frame */ 
     86    sport->put_buf = (pj_int16_t*) 
     87                     pj_pool_alloc(pool, dn_port->info.bytes_per_frame); 
     88 
     89    /* See if we need buffer for get_frame */ 
     90    if (dn_port->info.channel_count > channel_count) { 
     91        sport->get_buf = (pj_int16_t*) 
     92                         pj_pool_alloc(pool, dn_port->info.bytes_per_frame); 
     93    } 
     94 
     95    /* Media port interface */ 
     96    sport->base.get_frame = &stereo_get_frame; 
     97    sport->base.put_frame = &stereo_put_frame; 
     98    sport->base.on_destroy = &stereo_destroy; 
     99 
     100 
     101    /* Done */ 
     102    *p_port = &sport->base; 
     103 
     104    return PJ_SUCCESS; 
     105} 
     106 
     107static pj_status_t stereo_put_frame(pjmedia_port *this_port, 
     108                                    const pjmedia_frame *frame) 
     109{ 
     110    struct stereo_port *sport = (struct stereo_port*) this_port; 
     111    pjmedia_frame tmp_frame; 
     112 
     113    /* Return if we don't have downstream port. */ 
     114    if (sport->dn_port == NULL) { 
     115        return PJ_SUCCESS; 
     116    } 
     117 
     118    if (frame->type == PJMEDIA_FRAME_TYPE_AUDIO) { 
     119        tmp_frame.buf = sport->put_buf; 
     120        if (sport->dn_port->info.channel_count == 1) { 
     121            pjmedia_stereo_convert_to_mono(tmp_frame.buf, frame->buf, 
     122                                           sport->base.info.channel_count,  
     123                                           sport->dn_port->info.samples_per_frame,  
     124                                           sport->options); 
     125        } else { 
     126            pjmedia_stereo_convert_from_mono(tmp_frame.buf, frame->buf, 
     127                                             sport->dn_port->info.channel_count,  
     128                                             sport->base.info.samples_per_frame, 
     129                                             sport->options); 
     130        } 
     131        tmp_frame.size = sport->dn_port->info.bytes_per_frame; 
     132    } else { 
     133        tmp_frame.buf = frame->buf; 
     134        tmp_frame.size = frame->size; 
     135    } 
     136 
     137    tmp_frame.type = frame->type; 
     138    tmp_frame.timestamp.u64 = frame->timestamp.u64; 
     139 
     140    return pjmedia_port_put_frame( sport->dn_port, &tmp_frame ); 
     141} 
     142 
     143 
     144 
     145static pj_status_t stereo_get_frame(pjmedia_port *this_port,  
     146                                    pjmedia_frame *frame) 
     147{ 
     148    struct stereo_port *sport = (struct stereo_port*) this_port; 
     149    pjmedia_frame tmp_frame; 
     150    pj_status_t status; 
     151 
     152    /* Return silence if we don't have downstream port */ 
     153    if (sport->dn_port == NULL) { 
     154        pj_bzero(frame->buf, frame->size); 
     155        return PJ_SUCCESS; 
     156    } 
     157 
     158    tmp_frame.buf = sport->get_buf? sport->get_buf : frame->buf; 
     159    tmp_frame.size = sport->dn_port->info.bytes_per_frame; 
     160    tmp_frame.timestamp.u64 = frame->timestamp.u64; 
     161    tmp_frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
     162 
     163    status = pjmedia_port_get_frame( sport->dn_port, &tmp_frame); 
     164    if (status != PJ_SUCCESS) 
     165        return status; 
     166 
     167    if (tmp_frame.type != PJMEDIA_FRAME_TYPE_AUDIO) { 
     168        frame->type = tmp_frame.type; 
     169        frame->timestamp = tmp_frame.timestamp; 
     170        frame->size = tmp_frame.size; 
     171        if (tmp_frame.size && tmp_frame.buf == sport->get_buf) 
     172            pj_memcpy(frame->buf, tmp_frame.buf, tmp_frame.size); 
     173        return PJ_SUCCESS; 
     174    } 
     175 
     176    if (sport->base.info.channel_count == 1) { 
     177        pjmedia_stereo_convert_to_mono(frame->buf, tmp_frame.buf, 
     178                                       sport->dn_port->info.channel_count,  
     179                                       sport->base.info.samples_per_frame,  
     180                                       sport->options); 
     181    } else { 
     182        pjmedia_stereo_convert_from_mono(frame->buf, tmp_frame.buf, 
     183                                         sport->base.info.channel_count,  
     184                                         sport->dn_port->info.samples_per_frame, 
     185                                         sport->options); 
     186    } 
     187 
     188    frame->size = sport->base.info.bytes_per_frame; 
     189    frame->type = PJMEDIA_FRAME_TYPE_AUDIO; 
     190 
     191    return PJ_SUCCESS; 
     192} 
     193 
     194 
     195static pj_status_t stereo_destroy(pjmedia_port *this_port) 
     196{ 
     197    struct stereo_port *sport = (struct stereo_port*) this_port; 
     198 
     199    if ((sport->options & PJMEDIA_STEREO_DONT_DESTROY_DN)==0) { 
     200        pjmedia_port_destroy(sport->dn_port); 
     201        sport->dn_port = NULL; 
     202    } 
     203 
     204    return PJ_SUCCESS; 
     205} 
     206 
  • pjmedia/build/pjmedia.dsp

     
    237237# End Source File 
    238238# Begin Source File 
    239239 
     240SOURCE=..\src\pjmedia\stereo_port.c 
     241# End Source File 
     242# Begin Source File 
     243 
    240244SOURCE=..\src\pjmedia\stream.c 
    241245# End Source File 
    242246# Begin Source File 
     
    401405# End Source File 
    402406# Begin Source File 
    403407 
     408SOURCE=..\include\pjmedia\stereo.h 
     409# End Source File 
     410# Begin Source File 
     411 
    404412SOURCE=..\include\pjmedia\stream.h 
    405413# End Source File 
    406414# Begin Source File 
  • pjmedia/build/pjmedia.vcproj

     
    918918                                </FileConfiguration> 
    919919                        </File> 
    920920                        <File 
     921                                RelativePath="..\src\pjmedia\stereo_port.c" 
     922                                > 
     923                        </File> 
     924                        <File 
    921925                                RelativePath="..\src\pjmedia\stream.c" 
    922926                                > 
    923927                                <FileConfiguration 
     
    12091213                                > 
    12101214                        </File> 
    12111215                        <File 
     1216                                RelativePath="..\include\pjmedia\stereo.h" 
     1217                                > 
     1218                        </File> 
     1219                        <File 
    12121220                                RelativePath="..\include\pjmedia\stream.h" 
    12131221                                > 
    12141222                        </File> 
  • pjsip-apps/src/samples/stereotest.c

     
     1/* $Id$ */ 
     2/*  
     3 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> 
     4 * 
     5 * This program is free software; you can redistribute it and/or modify 
     6 * it under the terms of the GNU General Public License as published by 
     7 * the Free Software Foundation; either version 2 of the License, or 
     8 * (at your option) any later version. 
     9 * 
     10 * This program is distributed in the hope that it will be useful, 
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     13 * GNU General Public License for more details. 
     14 * 
     15 * You should have received a copy of the GNU General Public License 
     16 * along with this program; if not, write to the Free Software 
     17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
     18 */ 
     19 
     20/** 
     21 * \page page_pjmedia_samples_stereo_c Samples: Using Stereo Port 
     22 * 
     23 * This example demonstrates how to use @ref PJMEDIA_STEREO_PORT to 
     24 * change the channel count of the media streams. 
     25 * 
     26 * This file is pjsip-apps/src/samples/stereotest.c 
     27 * 
     28 * \includelineno stereotest.c 
     29 */ 
     30 
     31#include <pjmedia.h> 
     32#include <pjlib-util.h> 
     33#include <pjlib.h> 
     34 
     35#include <stdio.h> 
     36#include <stdlib.h> 
     37 
     38#include "util.h" 
     39 
     40#define REC_CLOCK_RATE      16000 
     41#define PTIME               10 
     42 
     43#define MODE_PLAY           1 
     44#define MODE_RECORD         2 
     45 
     46 
     47/* For logging purpose. */ 
     48#define THIS_FILE   "stereotest.c" 
     49 
     50 
     51static const char *desc =  
     52" FILE                                                              \n" 
     53"                                                                   \n" 
     54"  stereotest.c                                                     \n" 
     55"                                                                   \n" 
     56" PURPOSE                                                           \n" 
     57"                                                                   \n" 
     58"  Demonstrate how use stereo port to play a WAV file to sound      \n" 
     59"  device or record to a WAV file from sound device with different  \n" 
     60"  channel count.                                                   \n" 
     61"                                                                   \n" 
     62" USAGE                                                             \n" 
     63"                                                                   \n" 
     64"  stereotest [options] WAV                                         \n" 
     65"                                                                   \n" 
     66"  Options:                                                         \n" 
     67"  -m, --mode=N          Operation mode: 1 = playing, 2 = recording.\n" 
     68"  -C, --rec-ch-cnt=N    Number of channel for recording file.      \n" 
     69"  -c, --snd-ch-cnt=N    Number of channel for opening sound device.\n" 
     70"                                                                   \n"; 
     71 
     72int main(int argc, char *argv[]) 
     73{ 
     74    pj_caching_pool cp; 
     75    pjmedia_endpt *med_endpt; 
     76    pj_pool_t *pool; 
     77 
     78    pjmedia_port *file_port = NULL; 
     79    pjmedia_port *stereo_port = NULL; 
     80    pjmedia_snd_port *snd_port = NULL; 
     81 
     82    int dev_id = -1; 
     83    char tmp[10]; 
     84    pj_status_t status; 
     85 
     86    char *wav_file = NULL; 
     87    unsigned mode = 0; 
     88    unsigned rec_ch_cnt = 1; 
     89    unsigned snd_ch_cnt = 2; 
     90 
     91    enum { 
     92        OPT_MODE        = 'm', 
     93        OPT_REC_CHANNEL = 'C', 
     94        OPT_SND_CHANNEL = 'c', 
     95    }; 
     96 
     97    struct pj_getopt_option long_options[] = { 
     98        { "mode",           1, 0, OPT_MODE }, 
     99        { "rec-ch-cnt",     1, 0, OPT_REC_CHANNEL }, 
     100        { "snd-ch-cnt",     1, 0, OPT_SND_CHANNEL }, 
     101        { NULL, 0, 0, 0 }, 
     102    }; 
     103 
     104    int c; 
     105    int option_index; 
     106 
     107    /* Must init PJLIB first: */ 
     108    status = pj_init(); 
     109    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
     110 
     111    /* Parse arguments */ 
     112    pj_optind = 0; 
     113    while((c=pj_getopt_long(argc,argv, "m:C:c:", long_options, &option_index))!=-1) { 
     114 
     115        switch (c) { 
     116        case OPT_MODE: 
     117            if (mode) { 
     118                app_perror(THIS_FILE, "Cannot record and play at once!",  
     119                           PJ_EINVAL); 
     120                return 1; 
     121            } 
     122            mode = atoi(pj_optarg); 
     123            break; 
     124 
     125        case OPT_REC_CHANNEL: 
     126            rec_ch_cnt = atoi(pj_optarg); 
     127            break; 
     128 
     129        case OPT_SND_CHANNEL: 
     130            snd_ch_cnt = atoi(pj_optarg); 
     131            break; 
     132 
     133        default: 
     134            printf("Invalid options %s\n", argv[pj_optind]); 
     135            puts(desc); 
     136            return 1; 
     137        } 
     138 
     139    } 
     140 
     141    wav_file = argv[pj_optind]; 
     142 
     143    /* Verify arguments. */ 
     144    if (!wav_file) { 
     145        app_perror(THIS_FILE, "WAV file not specified!", PJ_EINVAL); 
     146        puts(desc); 
     147        return 1; 
     148    } 
     149    if (!snd_ch_cnt || !rec_ch_cnt || rec_ch_cnt > 6) { 
     150        app_perror(THIS_FILE, "Invalid or too many channel count!", PJ_EINVAL); 
     151        puts(desc); 
     152        return 1; 
     153    } 
     154    if (mode != MODE_RECORD && mode != MODE_PLAY) { 
     155        app_perror(THIS_FILE, "Invalid operation mode!", PJ_EINVAL); 
     156        puts(desc); 
     157        return 1; 
     158    } 
     159 
     160    /* Must create a pool factory before we can allocate any memory. */ 
     161    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); 
     162 
     163    /*  
     164     * Initialize media endpoint. 
     165     * This will implicitly initialize PJMEDIA too. 
     166     */ 
     167    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt); 
     168    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
     169 
     170    /* Create memory pool for our file player */ 
     171    pool = pj_pool_create( &cp.factory,     /* pool factory         */ 
     172                           "app",           /* pool name.           */ 
     173                           4000,            /* init size            */ 
     174                           4000,            /* increment size       */ 
     175                           NULL             /* callback on error    */ 
     176                           ); 
     177 
     178    if (mode == MODE_PLAY) { 
     179        /* Create WAVE file player port. */ 
     180        status = pjmedia_wav_player_port_create( pool, wav_file, PTIME, 0, 
     181                                                 0, &file_port); 
     182        if (status != PJ_SUCCESS) { 
     183            app_perror(THIS_FILE, "Unable to open file", status); 
     184            return 1; 
     185        } 
     186 
     187        /* Create sound player port. */ 
     188        status = pjmedia_snd_port_create_player(  
     189                     pool,                              /* pool               */ 
     190                     dev_id,                            /* device id.         */ 
     191                     file_port->info.clock_rate,        /* clock rate.        */ 
     192                     snd_ch_cnt,                        /* # of channels.     */ 
     193                     snd_ch_cnt * PTIME *               /* samples per frame. */ 
     194                     file_port->info.clock_rate / 1000, 
     195                     file_port->info.bits_per_sample,   /* bits per sample.   */ 
     196                     0,                                 /* options            */ 
     197                     &snd_port                          /* returned port      */ 
     198                     ); 
     199        if (status != PJ_SUCCESS) { 
     200            app_perror(THIS_FILE, "Unable to open sound device", status); 
     201            return 1; 
     202        } 
     203 
     204        if (snd_ch_cnt != file_port->info.channel_count) { 
     205            status = pjmedia_stereo_port_create( pool, 
     206                                                 file_port, 
     207                                                 snd_ch_cnt, 
     208                                                 0, 
     209                                                 &stereo_port); 
     210            if (status != PJ_SUCCESS) { 
     211                app_perror(THIS_FILE, "Unable to create stereo port", status); 
     212                return 1; 
     213            } 
     214 
     215            status = pjmedia_snd_port_connect(snd_port, stereo_port); 
     216        } else { 
     217            status = pjmedia_snd_port_connect(snd_port, file_port); 
     218        } 
     219 
     220        if (status != PJ_SUCCESS) { 
     221            app_perror(THIS_FILE, "Unable to connect sound port", status); 
     222            return 1; 
     223        } 
     224 
     225    } else { 
     226        /* Create WAVE file writer port. */ 
     227        status = pjmedia_wav_writer_port_create(pool, wav_file, 
     228                                                REC_CLOCK_RATE, 
     229                                                rec_ch_cnt, 
     230                                                rec_ch_cnt * PTIME *  
     231                                                REC_CLOCK_RATE / 1000, 
     232                                                NBITS, 
     233                                                0, 0,  
     234                                                &file_port); 
     235        if (status != PJ_SUCCESS) { 
     236            app_perror(THIS_FILE, "Unable to open file", status); 
     237            return 1; 
     238        } 
     239 
     240        /* Create sound player port. */ 
     241        status = pjmedia_snd_port_create_rec(  
     242                         pool,                      /* pool                 */ 
     243                         dev_id,                    /* device id.           */ 
     244                         REC_CLOCK_RATE,            /* clock rate.          */ 
     245                         snd_ch_cnt,                /* # of channels.       */ 
     246                         snd_ch_cnt * PTIME *  
     247                         REC_CLOCK_RATE / 1000,     /* samples per frame.   */ 
     248                         NBITS,                     /* bits per sample.     */ 
     249                         0,                         /* options              */ 
     250                         &snd_port                  /* returned port        */ 
     251                     ); 
     252        if (status != PJ_SUCCESS) { 
     253            app_perror(THIS_FILE, "Unable to open sound device", status); 
     254            return 1; 
     255        } 
     256 
     257        if (rec_ch_cnt != snd_ch_cnt) { 
     258            status = pjmedia_stereo_port_create( pool, 
     259                                                 file_port, 
     260                                                 snd_ch_cnt, 
     261                                                 0, 
     262                                                 &stereo_port); 
     263            if (status != PJ_SUCCESS) { 
     264                app_perror(THIS_FILE, "Unable to create stereo port", status); 
     265                return 1; 
     266            } 
     267 
     268            status = pjmedia_snd_port_connect(snd_port, stereo_port); 
     269        } else { 
     270            status = pjmedia_snd_port_connect(snd_port, file_port); 
     271        } 
     272 
     273        if (status != PJ_SUCCESS) { 
     274            app_perror(THIS_FILE, "Unable to connect sound port", status); 
     275            return 1; 
     276        } 
     277    } 
     278 
     279    /* Dump memory usage */ 
     280    dump_pool_usage(THIS_FILE, &cp); 
     281 
     282    /*  
     283     * File should be playing and looping now, using sound device's thread.  
     284     */ 
     285 
     286 
     287    /* Sleep to allow log messages to flush */ 
     288    pj_thread_sleep(100); 
     289 
     290    printf("Mode = %s\n", (mode == MODE_PLAY? "playing" : "recording") ); 
     291    printf("File  port channel count = %d\n", file_port->info.channel_count); 
     292    printf("Sound port channel count = %d\n",  
     293           pjmedia_snd_port_get_port(snd_port)->info.channel_count); 
     294    puts(""); 
     295    puts("Press <ENTER> to stop and quit"); 
     296 
     297    fgets(tmp, sizeof(tmp), stdin); 
     298 
     299     
     300    /* Start deinitialization: */ 
     301 
     302 
     303    /* Destroy sound device */ 
     304    status = pjmedia_snd_port_destroy( snd_port ); 
     305    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
     306 
     307 
     308    /* Destroy stereo port and file_port.  
     309     * Stereo port will destroy all downstream ports (e.g. the file port) 
     310     */ 
     311    status = pjmedia_port_destroy( stereo_port? stereo_port : file_port); 
     312    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
     313 
     314 
     315    /* Release application pool */ 
     316    pj_pool_release( pool ); 
     317 
     318    /* Destroy media endpoint. */ 
     319    pjmedia_endpt_destroy( med_endpt ); 
     320 
     321    /* Destroy pool factory */ 
     322    pj_caching_pool_destroy( &cp ); 
     323 
     324    /* Shutdown PJLIB */ 
     325    pj_shutdown(); 
     326 
     327 
     328    /* Done. */ 
     329    return 0; 
     330 
     331} 
     332 
     333 
     334 
  • pjmedia/include/pjmedia.h

     
    5151#include <pjmedia/sound.h> 
    5252#include <pjmedia/sound_port.h> 
    5353#include <pjmedia/splitcomb.h> 
     54#include <pjmedia/stereo.h> 
    5455#include <pjmedia/tonegen.h> 
    5556#include <pjmedia/transport.h> 
    5657#include <pjmedia/transport_ice.h>