[pjsip] PaRecorderCallback() and PaPlayerCallback() help

Nigel Hsiung nigelcz at hotmail.com
Fri Sep 14 09:56:28 EDT 2007



Hi Benny and list,

I've been checking out pjsip-0.7.0 for sometime and desperately need whatever help that u guys can.
All i want  is to run the whole pjsip package minus port audio, coz my sound system is a little bit different.

I took a leaf out of symbian_sound.cpp and modified pasound.c to fit my arm system. Using snd_info sample application i can see that it can open and close the audio correctly. Now i'm stuck at the callbacks - i'm unable to figure out how PaRecorderCallback() and PaPlayerCallback() performs audio read and write. For example in  - static int PaRecorderCallback(const void *input, 
                  void *output,
                  unsigned long frameCount,
                  //const PaStreamCallbackTimeInfo* timeInfo,
                  //PaStreamCallbackFlags statusFlags,
                  void *userData );
both *input and *output looks unused, while userData hold pj_media stream info. How does the function returns the audio data that was read.

Maybe i've done it wrong. Is there other ways to port pjmedia to a custom audio platform?

Thanks for the help,
Nigel

Modified pasound.c

/* $Id: pasound.c 1266 2007-05-11 15:14:34Z bennylp $ */
/* 
 * Copyright (C) 2003-2007 Benny Prijono <benny at 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 
 */
#include <pjmedia/sound.h>
#include <pjmedia/errno.h>
#include <pj/assert.h>
#include <pj/log.h>
#include <pj/os.h>
#include <pj/string.h>


#define ACC_MVL 1
#define CZDEBUG 1

#ifdef ACC_MVL
#include <errno.h>
typedef short Uint8;
#include "/home/nigel1/platform/kernel/linux-2.6.16.16/arch/arm/mach-mv88w8xx8/audio/audio.h"
//#include <signal.h>
//#include <sys/wait.h>
#include <fcntl.h>
//#include <sys/stat.h>
//#include <sys/mman.h>
//#include <sys/types.h>
//#include <sys/poll.h>
#define AUDIO_DEVICE_PATH "/dev/audio"
#define paUInt8 8
#define paInt16 16
#define paInt32 32
#define paAbort -1
#define paContinue 0
int audfd = -1; 
pjmedia_dir aud_dir;
#else
#include <portaudio.h>
#endif

#ifdef CZDEBUG
#define cztrace(x) printf x;
#else
#define cztrace(x) 
#endif

#if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_PORTAUDIO_SOUND

#define THIS_FILE    "pasound.c"

static int snd_init_count;

static struct snd_mgr
{
    pj_pool_factory *factory;
} snd_mgr;

/* 
 * Sound stream descriptor.
 * This struct may be used for both unidirectional or bidirectional sound
 * streams.
 */
struct pjmedia_snd_stream
{
    pj_pool_t        *pool;
    pj_str_t         name;
    pjmedia_dir         dir;
    int             play_id;
    int             rec_id;
    int             bytes_per_sample;
    pj_uint32_t         samples_per_sec;
    unsigned         samples_per_frame;
    int             channel_count;

//    PaStream        *rec_strm;
//    PaStream        *play_strm;

    void        *user_data;
    pjmedia_snd_rec_cb   rec_cb;
    pjmedia_snd_play_cb  play_cb;

    pj_uint32_t         timestamp;
    pj_uint32_t         underflow;
    pj_uint32_t         overflow;

    pj_bool_t         quit_flag;

    pj_bool_t         rec_thread_exited;
    pj_bool_t         rec_thread_initialized;
    pj_thread_desc     rec_thread_desc;
    pj_thread_t        *rec_thread;

    pj_bool_t         play_thread_exited;
    pj_bool_t         play_thread_initialized;
    pj_thread_desc     play_thread_desc;
    pj_thread_t        *play_thread;
};


static int PaRecorderCallback(const void *input, 
                  void *output,
                  unsigned long frameCount,
                  //const PaStreamCallbackTimeInfo* timeInfo,
                  //PaStreamCallbackFlags statusFlags,
                  void *userData )
{
cztrace(("PaRecorderCallback frameCount=%d\n", frameCount));
pjmedia_snd_stream *stream = (pjmedia_snd_stream*) userData;
//signed short buf[160];
//read(stream->rec_id, buf, 160);
//return read(stream->rec_id, output, frameCount);
#if 0
    pjmedia_snd_stream *stream = (pjmedia_snd_stream*) userData;
    pj_status_t status;

    //PJ_UNUSED_ARG(output);
    //PJ_UNUSED_ARG(timeInfo);

    if (stream->quit_flag){
    cztrace(("PaRecorderCallback stream->quit_flag\n"));
    goto on_break;
        }

    if (input == NULL){
    cztrace(("PaRecorderCallback input == NULL\n"));
    return paContinue;
        }

    if (stream->rec_thread_initialized == 0) {
    status = pj_thread_register("pa_rec", stream->rec_thread_desc, 
                    &stream->rec_thread);
    stream->rec_thread_initialized = 1;
    PJ_LOG(5,(THIS_FILE, "Recorder thread started"));
    }

//    if (statusFlags & paInputUnderflow)
//    ++stream->underflow;
//    if (statusFlags & paInputOverflow)
//    ++stream->overflow;

    stream->timestamp += frameCount;

    status = (*stream->rec_cb)(stream->user_data, stream->timestamp, 
                   (void*)input, 
                   frameCount * stream->bytes_per_sample *
                 stream->channel_count);
    
    if (status==0) 
    return paContinue;

on_break:
    stream->rec_thread_exited = 1;
    return paAbort;
#endif
}

static int PaPlayerCallback( const void *input, 
                 void *output,
                 unsigned long frameCount,
                 //const PaStreamCallbackTimeInfo* timeInfo,
                 //PaStreamCallbackFlags statusFlags,
                 void *userData )
{
#if 0
    pjmedia_snd_stream *stream = (pjmedia_snd_stream*) userData;
    pj_status_t status;
    unsigned size = frameCount * stream->bytes_per_sample *
            stream->channel_count;

    PJ_UNUSED_ARG(input);
//    PJ_UNUSED_ARG(timeInfo);

    if (stream->quit_flag){
    cztrace(("PaPlayerCallback stream->quit_flag\n"));
    goto on_break;
        }

    if (output == NULL){
    cztrace(("PaPlayerCallback output == NULL\n"));
    return paContinue;
        }

    if (stream->play_thread_initialized == 0) {
    status = pj_thread_register("portaudio", stream->play_thread_desc,
                    &stream->play_thread);
    stream->play_thread_initialized = 1;
    PJ_LOG(5,(THIS_FILE, "Player thread started"));
    }

//    if (statusFlags & paOutputUnderflow)
//    ++stream->underflow;
//   if (statusFlags & paOutputOverflow)
//    ++stream->overflow;

    stream->timestamp += frameCount;

    status = (*stream->play_cb)(stream->user_data, stream->timestamp, 
                    output, size);
    
    if (status==0) 
    return paContinue;

on_break:
    stream->play_thread_exited = 1;
    return paAbort;
#endif
}


static int PaRecorderPlayerCallback( const void *input, 
                     void *output,
                     unsigned long frameCount,
                     //const PaStreamCallbackTimeInfo* timeInfo,
                     //PaStreamCallbackFlags statusFlags,
                     void *userData )
{

    int rc;
    cztrace(("PaRecorderPlayerCallback\n"));

    rc = PaRecorderCallback(input, output, frameCount, userData);
    if (rc != paContinue)
    return rc;

    rc = PaPlayerCallback(input, output, frameCount, userData);
    return rc;
}

/* Logging callback from PA */
static void pa_log_cb(const char *log)
{
    PJ_LOG(5,(THIS_FILE, "PA message: %s", log));
}

/* We should include pa_debugprint.h for this, but the header
 * is not available publicly. :(
 */
typedef void (*PaUtilLogCallback ) (const char *log);
void PaUtil_SetDebugPrintFunction(PaUtilLogCallback  cb);

/*
 * Init sound library.
 */
PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
{
    cztrace(("pjmedia_snd_init\n"));
    if (++snd_init_count == 1) {
    int err;

    PaUtil_SetDebugPrintFunction(&pa_log_cb);

    snd_mgr.factory = factory;
    err = PJ_SUCCESS;

    PJ_LOG(4,(THIS_FILE, 
          "PortAudio sound library initialized, status=%d", err));
    //PJ_LOG(4,(THIS_FILE, "PortAudio host api count=%d",
    //             Pa_GetHostApiCount()));
    //PJ_LOG(4,(THIS_FILE, "Sound device count=%d",
    //             pjmedia_snd_get_dev_count()));

    return err;
    }

}


/*
 * Get device count.
 */
PJ_DEF(int) pjmedia_snd_get_dev_count(void)
{
    cztrace(("pjmedia_snd_get_dev_count\n"));
     return 1;
}


/*
 * Get device info.
 */
PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index)
{
    static pjmedia_snd_dev_info info;
    
    cztrace(("pjmedia_snd_get_dev_info index=%d\n", index));
        
        //if(index != audfd) return NULL;
        
    pj_bzero(&info, sizeof(info));
    strncpy(info.name, "ACC MVL SOUND", strlen("ACC MVL SOUND") ); //pa_info->name, sizeof(info.name));
    info.input_count = 1;  //pa_info->maxInputChannels;
    info.output_count = 1;  //pa_info->maxOutputChannels;
    info.default_samples_per_sec = 8000; //(unsigned)pa_info->defaultSampleRate;

    return &info;
}


/* Get PortAudio default input device ID */
static int pa_get_default_input_dev(int channel_count)
{
    cztrace(("pa_get_default_input_dev\n"));
        if(audfd!=-1) return audfd;
    else return -1;
}

/* Get PortAudio default output device ID */
static int pa_get_default_output_dev(int channel_count)
{
    cztrace(("pa_get_default_output_dev\n"));
    if(audfd!=-1) return audfd;
    else return -1;
}


/*
 * Open stream.
 */
PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
                      unsigned clock_rate,
                      unsigned channel_count,
                      unsigned samples_per_frame,
                      unsigned bits_per_sample,
                      pjmedia_snd_rec_cb rec_cb,
                      void *user_data,
                      pjmedia_snd_stream **p_snd_strm)
{
        cztrace(("pjmedia_snd_open_rec\n"));
    pj_pool_t *pool;
    pjmedia_snd_stream *stream;
    int sampleFormat;
    const pjmedia_snd_dev_info *paDevInfo = NULL;
    unsigned paFrames, paRate, paLatency;
    
    if(audfd<0){
       audfd = open(AUDIO_DEVICE_PATH, O_WRONLY);
       if (audfd < 0) {        
           pj_pool_release(pool);
           return -1;
        }
      }
      index = audfd; aud_dir=PJMEDIA_DIR_CAPTURE;
      
      paDevInfo = pjmedia_snd_get_dev_info(index);
      if (!paDevInfo) {
           /* Assumed it is "No such device" error. */
           return PJMEDIA_ESNDINDEVID;
        }

    if (bits_per_sample == 8)
    sampleFormat = paUInt8;
    else if (bits_per_sample == 16)
    sampleFormat = paInt16;
    else if (bits_per_sample == 32)
    sampleFormat = paInt32;
    else
    return PJMEDIA_ESNDINSAMPLEFMT;
    
    pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);
    if (!pool)
    return PJ_ENOMEM;

    stream = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_stream);
    stream->pool = pool;
    pj_strdup2_with_null(pool, &stream->name, paDevInfo->name);
    stream->dir = PJMEDIA_DIR_CAPTURE;
    stream->rec_id = index;
    stream->play_id = -1;
    stream->user_data = user_data;
    stream->samples_per_sec = clock_rate;
    stream->samples_per_frame = samples_per_frame;
    stream->bytes_per_sample = bits_per_sample / 8;
    stream->channel_count = channel_count;
    stream->rec_cb = rec_cb;

    /* Frames in PortAudio is number of samples in a single channel */
    paFrames = samples_per_frame / channel_count;

    paRate = 8000;
    paLatency = 16; //(unsigned)(paSI->inputLatency * 1000);

    PJ_LOG(5,(THIS_FILE, "Opened device %s (%s) for recording, sample "
             "rate=%d, ch=%d, "
             "bits=%d, %d samples per frame, latency=%d ms",
             paDevInfo->name, "ACC_MVL", //paHostApiInfo->name,
             paRate, channel_count,
             bits_per_sample, samples_per_frame,
             paLatency));

    *p_snd_strm = stream;
    return PJ_SUCCESS;
}


PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
                    unsigned clock_rate,
                    unsigned channel_count,
                    unsigned samples_per_frame,
                    unsigned bits_per_sample,
                    pjmedia_snd_play_cb play_cb,
                    void *user_data,
                    pjmedia_snd_stream **p_snd_strm)
{
        cztrace(("pjmedia_snd_open_player\n"));
    pj_pool_t *pool;
    pjmedia_snd_stream *stream;
    int sampleFormat;
    const pjmedia_snd_dev_info *paDevInfo = NULL;
    unsigned paFrames, paRate, paLatency;
    
    if(audfd<0){
       audfd = open(AUDIO_DEVICE_PATH, O_WRONLY);
       if (audfd < 0) {        
           pj_pool_release(pool);
           return -1;
        }
      }
      index = audfd; aud_dir=PJMEDIA_DIR_PLAYBACK;
      
      paDevInfo = pjmedia_snd_get_dev_info(index);
      if (!paDevInfo) {
           /* Assumed it is "No such device" error. */
           return PJMEDIA_ESNDINDEVID;
        }

   if (bits_per_sample == 8)
    sampleFormat = paUInt8;
    else if (bits_per_sample == 16)
    sampleFormat = paInt16;
    else if (bits_per_sample == 32)
    sampleFormat = paInt32;
    else
    return PJMEDIA_ESNDINSAMPLEFMT;
    
    pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);
    if (!pool)
    return PJ_ENOMEM;

    stream = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_stream);
    stream->pool = pool;
    pj_strdup2_with_null(pool, &stream->name, paDevInfo->name);
    stream->dir = stream->dir = PJMEDIA_DIR_PLAYBACK;
    stream->play_id = index;
    stream->rec_id = -1;
    stream->user_data = user_data;
    stream->samples_per_sec = clock_rate;
    stream->samples_per_frame = samples_per_frame;
    stream->bytes_per_sample = bits_per_sample / 8;
    stream->channel_count = channel_count;
    stream->play_cb = play_cb;


    paRate = 8000;
    paLatency = 16; //(unsigned)(paSI->outputLatency * 1000);

    PJ_LOG(5,(THIS_FILE, "Opened device %d: %s(%s) for playing, sample rate=%d"
             ", ch=%d, "
             "bits=%d, %d samples per frame, latency=%d ms",
             index, paDevInfo->name, "ACC_MVL", //paHostApiInfo->name, 
             paRate, channel_count,
              bits_per_sample, samples_per_frame, paLatency));

    *p_snd_strm = stream;

    return PJ_SUCCESS;
}


/*
 * Open both player and recorder.
 */
PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id,
                      int play_id,
                      unsigned clock_rate,
                      unsigned channel_count,
                      unsigned samples_per_frame,
                      unsigned bits_per_sample,
                      pjmedia_snd_rec_cb rec_cb,
                      pjmedia_snd_play_cb play_cb,
                      void *user_data,
                      pjmedia_snd_stream **p_snd_strm)
{    
    pj_pool_t *pool;
    pjmedia_snd_stream *stream;
    int sampleFormat;
    const pjmedia_snd_dev_info *paDevInfo = NULL;
    unsigned paFrames, paRate, paInputLatency, paOutputLatency;

    int arg, ret;
    unsigned char dataStr[2];
    
    if(clock_rate!=8000) return -1;
    cztrace(("pjmedia_snd_open rec_id=%d play_id=%d clock_rate=%d channel_count=%d\n", rec_id,play_id,clock_rate,channel_count));
    cztrace(("pjmedia_snd_open samples_per_frame=%d bits_per_sample=%d\n", samples_per_frame,bits_per_sample));
    
    

     if(audfd<0){
        audfd = open(AUDIO_DEVICE_PATH, O_RDWR);
        if (audfd < 0) {        
            printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
            goto err_out;    
        }        
     }
//#if 0
    arg = 0;    
    ret = ioctl(audfd, AUDIO_SET_MONO, arg);    
    if(ret < 0) {        
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
        goto err_out;    
        }        
    arg = 0;    
    ret = ioctl(audfd, AUDIO_SET_TXDISCARDTHRE, arg);    
    if(ret < 0) {          
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);          
        goto err_out;        
        }    
    arg = channel_count;    
    ret = ioctl(audfd, AUDIO_AKM_SET_CHANNEL, arg);    
    if(ret < 0) {        
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
        goto err_out;    
    }    
    arg = clock_rate;         /* sampling rate */    
    ret = ioctl(audfd, AUDIO_SET_SAMPLINGRATE, arg);    
    if(ret < 0) {        
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
        goto err_out;    
        }    
    arg = bits_per_sample;          /* sample size */    
    ret = ioctl(audfd, AUDIO_SET_TXBITPERSAMPLE, arg);    
    if(ret < 0) {        
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
        goto err_out;    
        }    
    arg = bits_per_sample;          /* sample size */    
    ret = ioctl(audfd, AUDIO_SET_RXBITPERSAMPLE, arg);    
    if(ret < 0) {        
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
        goto err_out;    
        }    
    arg = clock_rate;      /* sampling rate */    
    ret = ioctl(audfd, AUDIO_AKM_SET_SPEED, arg);    
    if(ret < 0) {        
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
        goto err_out;    
        }    
    arg = bits_per_sample;    
    ret = ioctl(audfd, AUDIO_AKM_SET_FMT, arg);    
    if(ret < 0) {        
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
        goto err_out;
        }    
    arg = 10;    
    ret = ioctl(audfd, AUDIO_SET_TXTRHESHOLD, arg);    
    if(ret < 0) {        
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
        goto err_out;    
        }    
    arg = 10;
    ret = ioctl(audfd, AUDIO_SET_RXTRHESHOLD, arg);    
    if(ret < 0) {        
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
        goto err_out;    
        }    
    arg = 54;         /* audio enable */    
    ret = ioctl(audfd, AUDIO_START_RXTX, arg);    
    if(ret < 0) {        
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
        goto err_out;    
        }    
    // vol    
    dataStr[0] = 0x0A;    
    dataStr[1] = 255-205;    
    ret = ioctl(audfd, AUDIO_SET_AKM_REG, dataStr);    
    if(ret < 0) {        
        printf("[%s-%d]-errno:%d\n", __FUNCTION__, __LINE__, errno);        
        goto err_out;    
        }
//#endif    
     cztrace(("pjmedia_snd_open audfd=%d\n", audfd));
     play_id = rec_id = audfd; aud_dir=PJMEDIA_DIR_CAPTURE_PLAYBACK;
     
     paDevInfo = pjmedia_snd_get_dev_info(rec_id);
     if (!paDevInfo) {
        /* Assumed it is "No such device" error. */
        return PJMEDIA_ESNDINDEVID;
       }


       if (bits_per_sample == 8)
       sampleFormat = paUInt8;
       else if (bits_per_sample == 16)
       sampleFormat = paInt16;
       else if (bits_per_sample == 32)
       sampleFormat = paInt32;
       else
       return PJMEDIA_ESNDINSAMPLEFMT;
    
    pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);
    if (!pool)
    return PJ_ENOMEM;

    stream = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_stream);
    stream->pool = pool;
    pj_strdup2_with_null(pool, &stream->name, paDevInfo->name);
    stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
    stream->play_id = play_id;
    stream->rec_id = rec_id;
    stream->user_data = user_data;
    stream->samples_per_sec = clock_rate;
    stream->samples_per_frame = samples_per_frame;
    stream->bytes_per_sample = bits_per_sample / 8;
    stream->channel_count = channel_count;
    stream->rec_cb = rec_cb;
    stream->play_cb = play_cb;

     /* Frames in PortAudio is number of samples in a single channel */
    paFrames = samples_per_frame / channel_count;
    paRate = 8000; //(unsigned)(paSI->sampleRate);
    paInputLatency = 16; //(unsigned)(paSI->inputLatency * 1000);
    paOutputLatency = 16;//(unsigned)(paSI->outputLatency * 1000);

    PJ_LOG(5,(THIS_FILE, "Opened device %s(%s)/%s(%s) for recording and "
             "playback, sample rate=%d, ch=%d, "
             "bits=%d, %d samples per frame, input latency=%d ms, "
             "output latency=%d ms",
             paDevInfo->name, "ACC_MVL", //paRecHostApiInfo->name,
             paDevInfo->name, "ACC_MVL", //paPlayHostApiInfo->name,
             paRate, channel_count,
             bits_per_sample, samples_per_frame,
             paInputLatency, paOutputLatency));

    *p_snd_strm = stream;
    return PJ_SUCCESS;

err_out:
    pj_pool_release(pool);    
    return PJ_RETURN_OS_ERROR(err);
}


/*
 * Get stream info.
 */
PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
                        pjmedia_snd_stream_info *pi)
{
    //const PaStreamInfo *paPlaySI = NULL, *paRecSI = NULL;
        cztrace(("pjmedia_snd_stream_get_info\n"));
    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
//    PJ_ASSERT_RETURN(strm->play_strm || strm->rec_strm, PJ_EINVALIDOP);



    pj_bzero(pi, sizeof(*pi));
    pi->dir =aud_dir;
    pi->play_id = audfd; //strm->play_id;
    pi->rec_id = audfd; //strm->rec_id;
    pi->clock_rate = 8000;
    pi->channel_count = 1;
    pi->samples_per_frame = 160; //num_of_channel x clock_rate x PTIME / 1000
    pi->bits_per_sample = 2 * 8; 
    pi->rec_latency = 16;
    pi->play_latency = 16;

    return PJ_SUCCESS;
}


/*
 * Start stream.
 */

PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
{
    int err = 0;
    int thread_status;
    cztrace(("pjmedia_snd_stream_start\n"));
    if (stream->play_id == stream->rec_id){
        thread_status = pthread_create( &stream->play_thread, NULL, PaRecorderPlayerCallback, stream );
        if(thread_status!=0){
            stream->play_thread_initialized=1;
            stream->play_thread_exited=0;
            stream->play_cb=PaRecorderPlayerCallback;

            stream->rec_thread_initialized=1;
            stream->rec_thread_exited=0;
            stream->rec_cb=PaRecorderPlayerCallback;
            }
        }else cztrace(("pjmedia_snd_stream_start stream->play_id != stream->rec_id \n"));

    PJ_LOG(5,(THIS_FILE, "Starting %s stream..", stream->name.ptr));
    PJ_LOG(5,(THIS_FILE, "Done, status=%d", err));

    return PJ_SUCCESS;
}
 
/*
 * Stop stream.
 */
PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
{
    int i, err = 0;
        cztrace(("pjmedia_snd_stream_stop\n"));
    stream->quit_flag = 1;

    PJ_LOG(5,(THIS_FILE, "Stopping stream.."));

    //pthread_cancel( &stream->play_thread);   /* XXX: Safe to call this if the thread has exited on its own? */
    pthread_join( &stream->play_thread, NULL );
    
    PJ_LOG(5,(THIS_FILE, "Done, status=%d", err));

    return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
}

/*
 * Destroy stream.
 */
PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
{
    /*
    if (stream->play_id ||stream->rec_id  ) {
        if(stream->play_id == stream->rec_id) close(stream->play_id);    
        else{
            if(stream->play_id >=0) close(stream->play_id);    
            if(stream->rec_id >=0) close(stream->rec_id);    
        }
    }
*/
    cztrace(("pjmedia_snd_stream_close\n"));
    if(audfd) {
        close(audfd);
        audfd=-1;
    }
    pj_pool_release(stream->pool);
    return PJ_SUCCESS;
}

/*
 * Deinitialize sound library.
 */
PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
{
    cztrace(("pjmedia_snd_deinit\n"));
    PJ_LOG(4,(THIS_FILE, "PortAudio sound library shutting down.."));
    return PJ_SUCCESS;
 
}


#endif    /* PJMEDIA_SOUND_IMPLEMENTATION */
 

_________________________________________________________________
Discover the new Windows Vista
http://search.msn.com/results.aspx?q=windows+vista&mkt=en-US&form=QBRE
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/attachments/20070914/f7bd7330/attachment.html>


More information about the pjsip mailing list