BLOG | DOCUMENTATION | TRAC

Home --> Documentations --> PJMEDIA Reference

Samples: Using Stereo Port

This example demonstrates how to use PJMEDIA_STEREO_PORT to change the channel count of the media streams.

This file is pjsip-apps/src/samples/stereotest.c

00001 /* $Id: stereotest.c 3664 2011-07-19 03:42:28Z nanang $ */
00002 /* 
00003  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
00004  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
00019  */
00020 
00032 #include <pjmedia.h>
00033 #include <pjlib-util.h>
00034 #include <pjlib.h>
00035 
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 
00039 #include "util.h"
00040 
00041 #define REC_CLOCK_RATE      16000
00042 #define PTIME               20
00043 
00044 #define MODE_PLAY           1
00045 #define MODE_RECORD         2
00046 
00047 
00048 /* For logging purpose. */
00049 #define THIS_FILE   "stereotest.c"
00050 
00051 
00052 static const char *desc = 
00053 " FILE                                                              \n"
00054 "                                                                   \n"
00055 "  stereotest.c                                                     \n"
00056 "                                                                   \n"
00057 " PURPOSE                                                           \n"
00058 "                                                                   \n"
00059 "  Demonstrate how use stereo port to play a WAV file to sound      \n"
00060 "  device or record to a WAV file from sound device with different  \n"
00061 "  channel count.                                                   \n"
00062 "                                                                   \n"
00063 " USAGE                                                             \n"
00064 "                                                                   \n"
00065 "  stereotest [options] WAV                                         \n"
00066 "                                                                   \n"
00067 "  Options:                                                         \n"
00068 "  -m, --mode=N          Operation mode: 1 = playing, 2 = recording.\n"
00069 "  -C, --rec-ch-cnt=N    Number of channel for recording file.      \n"
00070 "  -c, --snd-ch-cnt=N    Number of channel for opening sound device.\n"
00071 "                                                                   \n";
00072 
00073 int main(int argc, char *argv[])
00074 {
00075     pj_caching_pool cp;
00076     pjmedia_endpt *med_endpt;
00077     pj_pool_t *pool;
00078 
00079     pjmedia_port *file_port = NULL;
00080     pjmedia_port *stereo_port = NULL;
00081     pjmedia_snd_port *snd_port = NULL;
00082 
00083     int dev_id = -1;
00084     char tmp[10];
00085     pj_status_t status;
00086 
00087     char *wav_file = NULL;
00088     unsigned mode = 0;
00089     unsigned rec_ch_cnt = 1;
00090     unsigned snd_ch_cnt = 2;
00091 
00092     enum {
00093         OPT_MODE        = 'm',
00094         OPT_REC_CHANNEL = 'C',
00095         OPT_SND_CHANNEL = 'c',
00096     };
00097 
00098     struct pj_getopt_option long_options[] = {
00099         { "mode",           1, 0, OPT_MODE },
00100         { "rec-ch-cnt",     1, 0, OPT_REC_CHANNEL },
00101         { "snd-ch-cnt",     1, 0, OPT_SND_CHANNEL },
00102         { NULL, 0, 0, 0 },
00103     };
00104 
00105     int c;
00106     int option_index;
00107 
00108     /* Must init PJLIB first: */
00109     status = pj_init();
00110     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00111 
00112     /* Parse arguments */
00113     pj_optind = 0;
00114     while((c=pj_getopt_long(argc,argv, "m:C:c:", long_options, &option_index))!=-1) {
00115 
00116         switch (c) {
00117         case OPT_MODE:
00118             if (mode) {
00119                 app_perror(THIS_FILE, "Cannot record and play at once!", 
00120                            PJ_EINVAL);
00121                 return 1;
00122             }
00123             mode = atoi(pj_optarg);
00124             break;
00125 
00126         case OPT_REC_CHANNEL:
00127             rec_ch_cnt = atoi(pj_optarg);
00128             break;
00129 
00130         case OPT_SND_CHANNEL:
00131             snd_ch_cnt = atoi(pj_optarg);
00132             break;
00133 
00134         default:
00135             printf("Invalid options %s\n", argv[pj_optind]);
00136             puts(desc);
00137             return 1;
00138         }
00139 
00140     }
00141 
00142     wav_file = argv[pj_optind];
00143 
00144     /* Verify arguments. */
00145     if (!wav_file) {
00146         app_perror(THIS_FILE, "WAV file not specified!", PJ_EINVAL);
00147         puts(desc);
00148         return 1;
00149     }
00150     if (!snd_ch_cnt || !rec_ch_cnt || rec_ch_cnt > 6) {
00151         app_perror(THIS_FILE, "Invalid or too many channel count!", PJ_EINVAL);
00152         puts(desc);
00153         return 1;
00154     }
00155     if (mode != MODE_RECORD && mode != MODE_PLAY) {
00156         app_perror(THIS_FILE, "Invalid operation mode!", PJ_EINVAL);
00157         puts(desc);
00158         return 1;
00159     }
00160 
00161     /* Must create a pool factory before we can allocate any memory. */
00162     pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
00163 
00164     /* 
00165      * Initialize media endpoint.
00166      * This will implicitly initialize PJMEDIA too.
00167      */
00168     status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
00169     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00170 
00171     /* Create memory pool for our file player */
00172     pool = pj_pool_create( &cp.factory,     /* pool factory         */
00173                            "app",           /* pool name.           */
00174                            4000,            /* init size            */
00175                            4000,            /* increment size       */
00176                            NULL             /* callback on error    */
00177                            );
00178 
00179     if (mode == MODE_PLAY) {
00180         /* Create WAVE file player port. */
00181         status = pjmedia_wav_player_port_create( pool, wav_file, PTIME, 0,
00182                                                  0, &file_port);
00183         if (status != PJ_SUCCESS) {
00184             app_perror(THIS_FILE, "Unable to open file", status);
00185             return 1;
00186         }
00187 
00188         /* Create sound player port. */
00189         status = pjmedia_snd_port_create_player( 
00190                      pool,                              /* pool               */
00191                      dev_id,                            /* device id.         */
00192                      PJMEDIA_PIA_SRATE(&file_port->info),/* clock rate.       */
00193                      snd_ch_cnt,                        /* # of channels.     */
00194                      snd_ch_cnt * PTIME *               /* samples per frame. */
00195                      PJMEDIA_PIA_SRATE(&file_port->info) / 1000,
00196                      PJMEDIA_PIA_BITS(&file_port->info),/* bits per sample.   */
00197                      0,                                 /* options            */
00198                      &snd_port                          /* returned port      */
00199                      );
00200         if (status != PJ_SUCCESS) {
00201             app_perror(THIS_FILE, "Unable to open sound device", status);
00202             return 1;
00203         }
00204 
00205         if (snd_ch_cnt != PJMEDIA_PIA_CCNT(&file_port->info)) {
00206             status = pjmedia_stereo_port_create( pool,
00207                                                  file_port,
00208                                                  snd_ch_cnt,
00209                                                  0,
00210                                                  &stereo_port);
00211             if (status != PJ_SUCCESS) {
00212                 app_perror(THIS_FILE, "Unable to create stereo port", status);
00213                 return 1;
00214             }
00215 
00216             status = pjmedia_snd_port_connect(snd_port, stereo_port);
00217         } else {
00218             status = pjmedia_snd_port_connect(snd_port, file_port);
00219         }
00220 
00221         if (status != PJ_SUCCESS) {
00222             app_perror(THIS_FILE, "Unable to connect sound port", status);
00223             return 1;
00224         }
00225 
00226     } else {
00227         /* Create WAVE file writer port. */
00228         status = pjmedia_wav_writer_port_create(pool, wav_file,
00229                                                 REC_CLOCK_RATE,
00230                                                 rec_ch_cnt,
00231                                                 rec_ch_cnt * PTIME * 
00232                                                 REC_CLOCK_RATE / 1000,
00233                                                 NBITS,
00234                                                 0, 0, 
00235                                                 &file_port);
00236         if (status != PJ_SUCCESS) {
00237             app_perror(THIS_FILE, "Unable to open file", status);
00238             return 1;
00239         }
00240 
00241         /* Create sound player port. */
00242         status = pjmedia_snd_port_create_rec( 
00243                          pool,                      /* pool                 */
00244                          dev_id,                    /* device id.           */
00245                          REC_CLOCK_RATE,            /* clock rate.          */
00246                          snd_ch_cnt,                /* # of channels.       */
00247                          snd_ch_cnt * PTIME * 
00248                          REC_CLOCK_RATE / 1000,     /* samples per frame.   */
00249                          NBITS,                     /* bits per sample.     */
00250                          0,                         /* options              */
00251                          &snd_port                  /* returned port        */
00252                      );
00253         if (status != PJ_SUCCESS) {
00254             app_perror(THIS_FILE, "Unable to open sound device", status);
00255             return 1;
00256         }
00257 
00258         if (rec_ch_cnt != snd_ch_cnt) {
00259             status = pjmedia_stereo_port_create( pool,
00260                                                  file_port,
00261                                                  snd_ch_cnt,
00262                                                  0,
00263                                                  &stereo_port);
00264             if (status != PJ_SUCCESS) {
00265                 app_perror(THIS_FILE, "Unable to create stereo port", status);
00266                 return 1;
00267             }
00268 
00269             status = pjmedia_snd_port_connect(snd_port, stereo_port);
00270         } else {
00271             status = pjmedia_snd_port_connect(snd_port, file_port);
00272         }
00273 
00274         if (status != PJ_SUCCESS) {
00275             app_perror(THIS_FILE, "Unable to connect sound port", status);
00276             return 1;
00277         }
00278     }
00279 
00280     /* Dump memory usage */
00281     dump_pool_usage(THIS_FILE, &cp);
00282 
00283     /* 
00284      * File should be playing and looping now, using sound device's thread. 
00285      */
00286 
00287 
00288     /* Sleep to allow log messages to flush */
00289     pj_thread_sleep(100);
00290 
00291     printf("Mode = %s\n", (mode == MODE_PLAY? "playing" : "recording") );
00292     printf("File  port channel count = %d\n", PJMEDIA_PIA_CCNT(&file_port->info));
00293     printf("Sound port channel count = %d\n", 
00294             PJMEDIA_PIA_CCNT(&pjmedia_snd_port_get_port(snd_port)->info));
00295     puts("");
00296     puts("Press <ENTER> to stop and quit");
00297 
00298     if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
00299         puts("EOF while reading stdin, will quit now..");
00300     }
00301     
00302     /* Start deinitialization: */
00303 
00304 
00305     /* Destroy sound device */
00306     status = pjmedia_snd_port_destroy( snd_port );
00307     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00308 
00309 
00310     /* Destroy stereo port and file_port. 
00311      * Stereo port will destroy all downstream ports (e.g. the file port)
00312      */
00313     status = pjmedia_port_destroy( stereo_port? stereo_port : file_port);
00314     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00315 
00316 
00317     /* Release application pool */
00318     pj_pool_release( pool );
00319 
00320     /* Destroy media endpoint. */
00321     pjmedia_endpt_destroy( med_endpt );
00322 
00323     /* Destroy pool factory */
00324     pj_caching_pool_destroy( &cp );
00325 
00326     /* Shutdown PJLIB */
00327     pj_shutdown();
00328 
00329 
00330     /* Done. */
00331     return 0;
00332 
00333 }
00334 
00335 
00336 

 


PJMEDIA small footprint Open Source media stack
Copyright (C) 2006-2008 Teluu Inc.