Exemplo n.º 1
0
/* Internal: Create both player and recorder stream */
static pj_status_t create_bidir_stream(struct pa_aud_factory *pa,
				       const pjmedia_aud_param *param,
				       pjmedia_aud_rec_cb rec_cb,
				       pjmedia_aud_play_cb play_cb,
				       void *user_data,
				       pjmedia_aud_stream **p_snd_strm)
{
    pj_pool_t *pool;
    pjmedia_aud_dev_index rec_id, play_id;
    struct pa_aud_stream *stream;
    PaStream *paStream = NULL;
    PaStreamParameters inputParam;
    PaStreamParameters outputParam;
    int sampleFormat;
    const PaDeviceInfo *paRecDevInfo = NULL;
    const PaDeviceInfo *paPlayDevInfo = NULL;
    const PaHostApiInfo *paRecHostApiInfo = NULL;
    const PaHostApiInfo *paPlayHostApiInfo = NULL;
    const PaStreamInfo *paSI;
    unsigned paFrames, paRate, paInputLatency, paOutputLatency;
    PaError err;

    PJ_ASSERT_RETURN(play_cb && rec_cb && p_snd_strm, PJ_EINVAL);

    rec_id = param->rec_id;
    if (rec_id < 0) {
	rec_id = pa_get_default_input_dev(param->channel_count);
	if (rec_id < 0) {
	    /* No such device. */
	    return PJMEDIA_EAUD_NODEFDEV;
	}
    }

    paRecDevInfo = Pa_GetDeviceInfo(rec_id);
    if (!paRecDevInfo) {
	/* Assumed it is "No such device" error. */
	return PJMEDIA_EAUD_INVDEV;
    }

    play_id = param->play_id;
    if (play_id < 0) {
	play_id = pa_get_default_output_dev(param->channel_count);
	if (play_id < 0) {
	    /* No such device. */
	    return PJMEDIA_EAUD_NODEFDEV;
	}
    } 

    paPlayDevInfo = Pa_GetDeviceInfo(play_id);
    if (!paPlayDevInfo) {
	/* Assumed it is "No such device" error. */
	return PJMEDIA_EAUD_INVDEV;
    }


    if (param->bits_per_sample == 8)
	sampleFormat = paUInt8;
    else if (param->bits_per_sample == 16)
	sampleFormat = paInt16;
    else if (param->bits_per_sample == 32)
	sampleFormat = paInt32;
    else
	return PJMEDIA_EAUD_SAMPFORMAT;
    
    pool = pj_pool_create(pa->pf, "sndstream", 1024, 1024, NULL);
    if (!pool)
	return PJ_ENOMEM;

    stream = PJ_POOL_ZALLOC_T(pool, struct pa_aud_stream);
    stream->pool = pool;
    pj_strdup2_with_null(pool, &stream->name, paRecDevInfo->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 = param->clock_rate;
    stream->samples_per_frame = param->samples_per_frame;
    stream->bytes_per_sample = param->bits_per_sample / 8;
    stream->channel_count = param->channel_count;
    stream->rec_cb = rec_cb;
    stream->play_cb = play_cb;

    stream->rec_buf = (pj_int16_t*)pj_pool_alloc(pool, 
		      stream->samples_per_frame * stream->bytes_per_sample);
    stream->rec_buf_count = 0;

    stream->play_buf = (pj_int16_t*)pj_pool_alloc(pool, 
		       stream->samples_per_frame * stream->bytes_per_sample);
    stream->play_buf_count = 0;

    pj_bzero(&inputParam, sizeof(inputParam));
    inputParam.device = rec_id;
    inputParam.channelCount = param->channel_count;
    inputParam.hostApiSpecificStreamInfo = NULL;
    inputParam.sampleFormat = sampleFormat;
    if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY)
	inputParam.suggestedLatency = param->input_latency_ms / 1000.0;
    else
	inputParam.suggestedLatency = PJMEDIA_SND_DEFAULT_REC_LATENCY / 1000.0;

    paRecHostApiInfo = Pa_GetHostApiInfo(paRecDevInfo->hostApi);

    pj_bzero(&outputParam, sizeof(outputParam));
    outputParam.device = play_id;
    outputParam.channelCount = param->channel_count;
    outputParam.hostApiSpecificStreamInfo = NULL;
    outputParam.sampleFormat = sampleFormat;
    if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY)
	outputParam.suggestedLatency=param->output_latency_ms / 1000.0;
    else
	outputParam.suggestedLatency=PJMEDIA_SND_DEFAULT_PLAY_LATENCY/1000.0;

    paPlayHostApiInfo = Pa_GetHostApiInfo(paPlayDevInfo->hostApi);

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

    /* If both input and output are on the same device, open a single stream
     * for both input and output.
     */
    if (rec_id == play_id) {
	err = Pa_OpenStream( &paStream, &inputParam, &outputParam,
			     param->clock_rate, paFrames, 
			     paClipOff, &PaRecorderPlayerCallback, stream );
	if (err == paNoError) {
	    /* Set play stream and record stream to the same stream */
	    stream->play_strm = stream->rec_strm = paStream;
	}
    } else {
	err = -1;
    }

    /* .. otherwise if input and output are on the same device, OR if we're
     * unable to open a bidirectional stream, then open two separate
     * input and output stream.
     */
    if (paStream == NULL) {
	/* Open input stream */
	err = Pa_OpenStream( &stream->rec_strm, &inputParam, NULL,
			     param->clock_rate, paFrames, 
			     paClipOff, &PaRecorderCallback, stream );
	if (err == paNoError) {
	    /* Open output stream */
	    err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam,
				 param->clock_rate, paFrames, 
				 paClipOff, &PaPlayerCallback, stream );
	    if (err != paNoError)
		Pa_CloseStream(stream->rec_strm);
	}
    }

    if (err != paNoError) {
	pj_pool_release(pool);
	return PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err);
    }

    paSI = Pa_GetStreamInfo(stream->rec_strm);
    paRate = (unsigned)(paSI->sampleRate);
    paInputLatency = (unsigned)(paSI->inputLatency * 1000);
    paSI = Pa_GetStreamInfo(stream->play_strm);
    paOutputLatency = (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",
			 paRecDevInfo->name, paRecHostApiInfo->name,
			 paPlayDevInfo->name, paPlayHostApiInfo->name,
			 paRate, param->channel_count,
			 param->bits_per_sample, param->samples_per_frame,
			 paInputLatency, paOutputLatency));

    *p_snd_strm = &stream->base;

    return PJ_SUCCESS;
}
Exemplo n.º 2
0
/*
 * Open both player and recorder.
 */
PJ_DEF(pj_status_t) pjmedia_snd_open( int *prec_id,
				      int *pplay_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;
    PaStream *paStream = NULL;
    PaStreamParameters inputParam;
    PaStreamParameters outputParam;
    int sampleFormat;
    const PaDeviceInfo *paRecDevInfo = NULL;
    const PaDeviceInfo *paPlayDevInfo = NULL;
    const PaHostApiInfo *paRecHostApiInfo = NULL;
    const PaHostApiInfo *paPlayHostApiInfo = NULL;
    const PaStreamInfo *paSI;
    unsigned paFrames, paRate, paInputLatency, paOutputLatency;
    PaError err;

    if (*prec_id < 0) {
	*prec_id = pa_get_default_input_dev(channel_count);
	if (*prec_id < 0) {
	    /* No such device. */
	    return PJMEDIA_ENOSNDREC;
	}
    }
    int rec_id=*prec_id;
    paRecDevInfo = Pa_GetDeviceInfo(rec_id);
    if (!paRecDevInfo) {
	/* Assumed it is "No such device" error. */
	return PJMEDIA_ESNDINDEVID;
    }

    if (*pplay_id < 0) {
	*pplay_id = pa_get_default_output_dev(channel_count);
	if (*pplay_id < 0) {
	    /* No such device. */
	    return PJMEDIA_ENOSNDPLAY;
	}
    } 
    int play_id=*pplay_id;
    paPlayDevInfo = Pa_GetDeviceInfo(play_id);
    if (!paPlayDevInfo) {
	/* 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(pool, sizeof(*stream));
    stream->pool = pool;
    pj_strdup2_with_null(pool, &stream->name, paRecDevInfo->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;

    pj_bzero(&inputParam, sizeof(inputParam));
    inputParam.device = rec_id;
    inputParam.channelCount = channel_count;
    inputParam.hostApiSpecificStreamInfo = NULL;
    inputParam.sampleFormat = sampleFormat;
    inputParam.suggestedLatency = paRecDevInfo->defaultLowInputLatency;

    paRecHostApiInfo = Pa_GetHostApiInfo(paRecDevInfo->hostApi);

    pj_bzero(&outputParam, sizeof(outputParam));
    outputParam.device = play_id;
    outputParam.channelCount = channel_count;
    outputParam.hostApiSpecificStreamInfo = NULL;
    outputParam.sampleFormat = sampleFormat;
    outputParam.suggestedLatency = paPlayDevInfo->defaultLowOutputLatency;

    paPlayHostApiInfo = Pa_GetHostApiInfo(paPlayDevInfo->hostApi);

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

    /* If both input and output are on the same device, open a single stream
     * for both input and output.
     */
    if (rec_id == play_id) {
	err = Pa_OpenStream( &paStream, &inputParam, &outputParam,
			     clock_rate, paFrames, 
			     paClipOff, &PaRecorderPlayerCallback, stream );
	if (err == paNoError) {
	    /* Set play stream and record stream to the same stream */
	    stream->play_strm = stream->rec_strm = paStream;
	}
    } else {
	err = -1;
    }

    /* .. otherwise if input and output are on the same device, OR if we're
     * unable to open a bidirectional stream, then open two separate
     * input and output stream.
     */
    if (paStream == NULL) {
	/* Open input stream */
	err = Pa_OpenStream( &stream->rec_strm, &inputParam, NULL,
			     clock_rate, paFrames, 
			     paClipOff, &PaRecorderCallback, stream );
	if (err == paNoError) {
	    /* Open output stream */
	    err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam,
				 clock_rate, paFrames, 
				 paClipOff, &PaPlayerCallback, stream );
	    if (err != paNoError)
		Pa_CloseStream(stream->rec_strm);
	}
    }

    if (err != paNoError) {
	pj_pool_release(pool);
	return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
    }

    paSI = Pa_GetStreamInfo(stream->rec_strm);
    paRate = (unsigned)(paSI->sampleRate);
    paInputLatency = (unsigned)(paSI->inputLatency * 1000);
    paSI = Pa_GetStreamInfo(stream->play_strm);
    paOutputLatency = (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",
			 paRecDevInfo->name, paRecHostApiInfo->name,
			 paPlayDevInfo->name, paPlayHostApiInfo->name,
			 paRate, channel_count,
			 bits_per_sample, samples_per_frame,
			 paInputLatency, paOutputLatency));

    *p_snd_strm = stream;


    return PJ_SUCCESS;
}
Exemplo n.º 3
0
/* Internal: create capture/recorder stream */
static pj_status_t create_rec_stream( struct pa_aud_factory *pa,
				      const pjmedia_aud_param *param,
				      pjmedia_aud_rec_cb rec_cb,
				      void *user_data,
				      pjmedia_aud_stream **p_snd_strm)
{
    pj_pool_t *pool;
    pjmedia_aud_dev_index rec_id;
    struct pa_aud_stream *stream;
    PaStreamParameters inputParam;
    int sampleFormat;
    const PaDeviceInfo *paDevInfo = NULL;
    const PaHostApiInfo *paHostApiInfo = NULL;
    unsigned paFrames, paRate, paLatency;
    const PaStreamInfo *paSI;
    PaError err;

    PJ_ASSERT_RETURN(rec_cb && p_snd_strm, PJ_EINVAL);

    rec_id = param->rec_id;
    if (rec_id < 0) {
	rec_id = pa_get_default_input_dev(param->channel_count);
	if (rec_id < 0) {
	    /* No such device. */
	    return PJMEDIA_EAUD_NODEFDEV;
	}
    }

    paDevInfo = Pa_GetDeviceInfo(rec_id);
    if (!paDevInfo) {
	/* Assumed it is "No such device" error. */
	return PJMEDIA_EAUD_INVDEV;
    }

    if (param->bits_per_sample == 8)
	sampleFormat = paUInt8;
    else if (param->bits_per_sample == 16)
	sampleFormat = paInt16;
    else if (param->bits_per_sample == 32)
	sampleFormat = paInt32;
    else
	return PJMEDIA_EAUD_SAMPFORMAT;
    
    pool = pj_pool_create(pa->pf, "recstrm", 1024, 1024, NULL);
    if (!pool)
	return PJ_ENOMEM;

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

    stream->rec_buf = (pj_int16_t*)pj_pool_alloc(pool, 
		      stream->samples_per_frame * stream->bytes_per_sample);
    stream->rec_buf_count = 0;

    pj_bzero(&inputParam, sizeof(inputParam));
    inputParam.device = rec_id;
    inputParam.channelCount = param->channel_count;
    inputParam.hostApiSpecificStreamInfo = NULL;
    inputParam.sampleFormat = sampleFormat;
    if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY)
	inputParam.suggestedLatency = param->input_latency_ms / 1000.0;
    else
	inputParam.suggestedLatency = PJMEDIA_SND_DEFAULT_REC_LATENCY / 1000.0;

    paHostApiInfo = Pa_GetHostApiInfo(paDevInfo->hostApi);

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

    err = Pa_OpenStream( &stream->rec_strm, &inputParam, NULL,
			 param->clock_rate, paFrames, 
			 paClipOff, &PaRecorderCallback, stream );
    if (err != paNoError) {
	pj_pool_release(pool);
	return PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err);
    }

    paSI = Pa_GetStreamInfo(stream->rec_strm);
    paRate = (unsigned)paSI->sampleRate;
    paLatency = (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, paHostApiInfo->name,
			 paRate, param->channel_count,
			 param->bits_per_sample, param->samples_per_frame,
			 paLatency));

    *p_snd_strm = &stream->base;
    return PJ_SUCCESS;
}
Exemplo n.º 4
0
/*
 * Open stream.
 */
PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int *pindex,
					  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)
{
    pj_pool_t *pool;
    pjmedia_snd_stream *stream;
    PaStreamParameters inputParam;
    int sampleFormat;
    const PaDeviceInfo *paDevInfo = NULL;
    const PaHostApiInfo *paHostApiInfo = NULL;
    unsigned paFrames, paRate, paLatency;
    const PaStreamInfo *paSI;
    PaError err;

    if (*pindex < 0) {
	*pindex = pa_get_default_input_dev(channel_count);
	if (index < 0) {
	    /* No such device. */
	    return PJMEDIA_ENOSNDREC;
	}
    }
    int index=*pindex;
    paDevInfo = Pa_GetDeviceInfo(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(pool, sizeof(*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;

    pj_bzero(&inputParam, sizeof(inputParam));
    inputParam.device = index;
    inputParam.channelCount = channel_count;
    inputParam.hostApiSpecificStreamInfo = NULL;
    inputParam.sampleFormat = sampleFormat;
    inputParam.suggestedLatency = paDevInfo->defaultLowInputLatency;

    paHostApiInfo = Pa_GetHostApiInfo(paDevInfo->hostApi);

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

    err = Pa_OpenStream( &stream->rec_strm, &inputParam, NULL,
			 clock_rate, paFrames, 
			 paClipOff, &PaRecorderCallback, stream );
    if (err != paNoError) {
	pj_pool_release(pool);
	return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
    }

    paSI = Pa_GetStreamInfo(stream->rec_strm);
    paRate = (unsigned)paSI->sampleRate;
    paLatency = (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, paHostApiInfo->name,
			 paRate, channel_count,
			 bits_per_sample, samples_per_frame,
			 paLatency));

    *p_snd_strm = stream;
    return PJ_SUCCESS;
}