static pj_status_t bb10_open_playback (struct bb10_stream *stream, const pjmedia_aud_param *param) { int ret = 0; snd_pcm_channel_info_t pi; snd_pcm_channel_setup_t setup; snd_mixer_group_t group; snd_pcm_channel_params_t pp; unsigned int rate; unsigned long tmp_buf_size; if (param->play_id < 0 || param->play_id >= stream->af->dev_cnt) { return PJMEDIA_EAUD_INVDEV; } PJ_ASSERT_RETURN(param->bits_per_sample == 16, PJMEDIA_EAUD_SAMPFORMAT); /* Use the bb10 audio manager API to open as opposed to QNX core audio * Echo cancellation built in */ if ((ret = audio_manager_snd_pcm_open_name( AUDIO_TYPE_VIDEO_CHAT, &stream->pb_pcm, &stream->pb_audio_manager_handle, (char*)"voice", SND_PCM_OPEN_PLAYBACK)) < 0) { TRACE_((THIS_FILE, "audio_manager_snd_pcm_open_name ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } /* Required call from January 2013 gold OS release */ snd_pcm_plugin_set_disable(stream->pb_pcm, PLUGIN_DISABLE_MMAP); /* Required call from January 2013 gold OS release */ snd_pcm_plugin_set_enable(stream->pb_pcm, PLUGIN_ROUTING); memset (&pi, 0, sizeof (pi)); pi.channel = SND_PCM_CHANNEL_PLAYBACK; if ((ret = snd_pcm_plugin_info (stream->pb_pcm, &pi)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_info ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } memset (&pp, 0, sizeof (pp)); /* Request VoIP compatible capabilities */ pp.mode = SND_PCM_MODE_BLOCK; pp.channel = SND_PCM_CHANNEL_PLAYBACK; pp.start_mode = SND_PCM_START_FULL; pp.stop_mode = SND_PCM_STOP_ROLLOVER; pp.buf.block.frag_size = param->samples_per_frame * param->bits_per_sample / 8; /* RIM recommends maximum of 5 */ pp.buf.block.frags_max = 5; pp.buf.block.frags_min = 1; pp.format.interleave = 1; pp.format.rate = param->clock_rate; pp.format.voices = param->channel_count; pp.format.format = get_alsa_pcm_fmt(param); /* Make the calls as per the wave sample */ if ((ret = snd_pcm_plugin_params (stream->pb_pcm, &pp)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_params ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } memset (&setup, 0, sizeof (setup)); memset (&group, 0, sizeof (group)); setup.channel = SND_PCM_CHANNEL_PLAYBACK; setup.mixer_gid = &group.gid; if ((ret = snd_pcm_plugin_setup (stream->pb_pcm, &setup)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_setup ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } if (group.gid.name[0] == 0) { return PJMEDIA_EAUD_SYSERR; } rate = param->clock_rate; /* Set the sound device buffer size and latency */ if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY) { tmp_buf_size = rate * param->output_latency_ms / 1000; } else { tmp_buf_size = rate * PJMEDIA_SND_DEFAULT_PLAY_LATENCY / 1000; } /* Set period size to samples_per_frame frames. */ stream->pb_frames = param->samples_per_frame / param->channel_count; stream->param.output_latency_ms = tmp_buf_size * 1000 / rate; /* Set our buffer */ stream->pb_buf_size = stream->pb_frames * param->channel_count * param->bits_per_sample / 8; stream->pb_buf = (char *) pj_pool_alloc(stream->pool, stream->pb_buf_size); TRACE_((THIS_FILE, "bb10_open_playback: pb_frames = %d clock = %d", stream->pb_frames, param->clock_rate)); return PJ_SUCCESS; }
static pj_status_t bb10_open_capture (struct bb10_stream *stream, const pjmedia_aud_param *param) { int ret = 0; unsigned int rate; unsigned long tmp_buf_size; int frame_size; snd_pcm_channel_info_t pi; snd_mixer_group_t group; snd_pcm_channel_params_t pp; snd_pcm_channel_setup_t setup; if (param->rec_id < 0 || param->rec_id >= stream->af->dev_cnt) return PJMEDIA_EAUD_INVDEV; PJ_ASSERT_RETURN(param->bits_per_sample == 16, PJMEDIA_EAUD_SAMPFORMAT); if ((ret=audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT, &stream->ca_pcm, &stream->ca_audio_manager_handle, (char*)"voice", SND_PCM_OPEN_CAPTURE)) < 0) { TRACE_((THIS_FILE, "audio_manager_snd_pcm_open_name ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } /* Required call from January 2013 gold OS release */ snd_pcm_plugin_set_disable (stream->ca_pcm, PLUGIN_DISABLE_MMAP); /* Required call from January 2013 gold OS release */ snd_pcm_plugin_set_enable(stream->ca_pcm, PLUGIN_ROUTING); /* sample reads the capabilities of the capture */ memset (&pi, 0, sizeof (pi)); pi.channel = SND_PCM_CHANNEL_CAPTURE; if ((ret = snd_pcm_plugin_info (stream->ca_pcm, &pi)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_info ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } /* Request the VoIP parameters * These parameters are different to waverec sample */ memset (&pp, 0, sizeof (pp)); /* Blocking read */ pp.mode = SND_PCM_MODE_BLOCK; pp.channel = SND_PCM_CHANNEL_CAPTURE; pp.start_mode = SND_PCM_START_FULL; /* Auto-recover from errors */ pp.stop_mode = SND_PCM_STOP_ROLLOVER; pp.buf.block.frag_size = param->samples_per_frame * param->bits_per_sample / 8; /* From January 2013 gold OS release. RIM recommend these for capture */ pp.buf.block.frags_max = 3; pp.buf.block.frags_min = 1; pp.format.interleave = 1; pp.format.rate = param->clock_rate; pp.format.voices = param->channel_count; pp.format.format = get_alsa_pcm_fmt(param); /* make the request */ if ((ret = snd_pcm_plugin_params (stream->ca_pcm, &pp)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_params ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } /* Again based on the sample */ memset (&setup, 0, sizeof (setup)); memset (&group, 0, sizeof (group)); setup.channel = SND_PCM_CHANNEL_CAPTURE; setup.mixer_gid = &group.gid; if ((ret = snd_pcm_plugin_setup (stream->ca_pcm, &setup)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_setup ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } frame_size = setup.buf.block.frag_size; if (group.gid.name[0] == 0) { } else { } frame_size = setup.buf.block.frag_size; PJ_UNUSED_ARG(frame_size); /* Warning about unused var */ /* Set clock rate */ rate = param->clock_rate; stream->ca_frames = (unsigned long) param->samples_per_frame / param->channel_count; /* Set the sound device buffer size and latency */ if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY) { tmp_buf_size = rate * param->input_latency_ms / 1000; } else { tmp_buf_size = rate * PJMEDIA_SND_DEFAULT_REC_LATENCY / 1000; } stream->param.input_latency_ms = tmp_buf_size * 1000 / rate; /* Set our buffer */ stream->ca_buf_size = stream->ca_frames * param->channel_count * param->bits_per_sample / 8; stream->ca_buf = (char *)pj_pool_alloc (stream->pool, stream->ca_buf_size); TRACE_((THIS_FILE, "bb10_open_capture: ca_frames = %d clock = %d", stream->ca_frames, param->clock_rate)); return PJ_SUCCESS; }
/* * BB10 - tests loads the audio units and sets up the driver structure */ static pj_status_t bb10_add_dev (struct bb10_factory *af) { pjmedia_aud_dev_info *adi; int pb_result, ca_result; unsigned int handle; snd_pcm_t *pcm_handle; if (af->dev_cnt >= PJ_ARRAY_SIZE(af->devs)) return PJ_ETOOMANY; adi = &af->devs[af->dev_cnt]; TRACE_((THIS_FILE, "bb10_add_dev Enter")); if ((pb_result = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT, &pcm_handle, &handle, (char*)"voice", SND_PCM_OPEN_PLAYBACK)) >= 0) { snd_pcm_close (pcm_handle); audio_manager_free_handle(handle); } else { TRACE_((THIS_FILE, "Try to open the device for playback - failure")); } if ((ca_result = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT, &pcm_handle, &handle, (char*)"voice", SND_PCM_OPEN_CAPTURE)) >= 0) { snd_pcm_close (pcm_handle); audio_manager_free_handle(handle); } else { TRACE_((THIS_FILE, "Try to open the device for capture - failure")); } if (pb_result < 0 && ca_result < 0) { TRACE_((THIS_FILE, "Unable to open sound device", "preferred")); return PJMEDIA_EAUD_NODEV; } /* Reset device info */ pj_bzero(adi, sizeof(*adi)); /* Set device name */ strcpy(adi->name, "preferred"); /* Check the number of playback channels */ adi->output_count = (pb_result >= 0) ? 1 : 0; /* Check the number of capture channels */ adi->input_count = (ca_result >= 0) ? 1 : 0; /* Set the default sample rate */ adi->default_samples_per_sec = 8000; /* Driver name */ strcpy(adi->driver, "BB10"); ++af->dev_cnt; PJ_LOG (4,(THIS_FILE, "Added sound device %s", adi->name)); return PJ_SUCCESS; }
static void playsetup() { snd_pcm_channel_setup_t setup; //Enabling Echo canceller int ret; snd_pcm_channel_info_t pi; snd_mixer_group_t group; snd_pcm_channel_params_t pp; //audio routing enabled with AEC if ((ret = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT, &g_pcm_handle_p, &g_audio_manager_handle_p, (char*) "voice", SND_PCM_OPEN_PLAYBACK)) < 0) { return; } snd_pcm_plugin_set_disable(g_pcm_handle_p, PLUGIN_DISABLE_MMAP); snd_pcm_plugin_set_enable(g_pcm_handle_p, PLUGIN_ROUTING); memset(&pi, 0, sizeof(pi)); pi.channel = SND_PCM_CHANNEL_PLAYBACK; if ((ret = snd_pcm_plugin_info(g_pcm_handle_p, &pi)) < 0) { fprintf(stderr, "snd_pcm_plugin_info failed: %s\n", snd_strerror (ret)); return; } fprintf(stderr,"PLAY Minimum Rate = %d\n",pi.min_rate); // Interestingly on the simulator this returns 4096 but in reality always 170 is the result fprintf(stderr,"PLAY Minimum fragment size = %d\n",pi.min_fragment_size); memset(&pp, 0, sizeof(pp)); // Request VoIP compatible capabilities // On simulator frag_size is always negotiated to 170 pp.mode = SND_PCM_MODE_BLOCK; pp.channel = SND_PCM_CHANNEL_PLAYBACK; //pp.start_mode = SND_PCM_START_DATA; pp.stop_mode = SND_PCM_STOP_ROLLOVER; pp.start_mode = SND_PCM_START_FULL; pp.buf.block.frag_size = PREFERRED_FRAME_SIZE; // Increasing this internal buffer count delays write failure in the loop pp.buf.block.frags_max = 5; pp.buf.block.frags_min = 1; pp.format.interleave = 1; pp.format.rate = VOIP_SAMPLE_RATE; pp.format.voices = 1; pp.format.format = SND_PCM_SFMT_S16_LE; // Make the calls as per the wave sample if ((ret = snd_pcm_plugin_params(g_pcm_handle_p, &pp)) < 0) { fprintf(stderr, "pb snd_pcm_plugin_params failed: %s\n", snd_strerror (ret)); return; } memset(&setup, 0, sizeof(setup)); memset(&group, 0, sizeof(group)); setup.channel = SND_PCM_CHANNEL_PLAYBACK; setup.mixer_gid = &group.gid; if ((ret = snd_pcm_plugin_setup(g_pcm_handle_p, &setup)) < 0) { fprintf(stderr, "snd_pcm_plugin_setup failed: %s\n", snd_strerror (ret)); return; } fprintf(stderr,"PLAY frame_size %d \n", setup.buf.block.frag_size); fprintf(stderr,"PLAY Rate %d \n", setup.format.rate); g_frame_size_p = setup.buf.block.frag_size; if (group.gid.name[0] == 0) { fprintf(stderr,"FATAL Mixer Pcm Group [%s] Not Set \n", group.gid.name); exit (-1); } printf("Mixer Pcm Group [%s]\n", group.gid.name); if ((ret = snd_pcm_plugin_prepare(g_pcm_handle_p, SND_PCM_CHANNEL_PLAYBACK)) < 0) { fprintf(stderr, "snd_pcm_plugin_prepare failed: %s\n", snd_strerror (ret)); } }
static void capturesetup() { snd_pcm_channel_setup_t setup; int ret; snd_pcm_channel_info_t pi; snd_mixer_group_t group; snd_pcm_channel_params_t pp; int card = setup.mixer_card; if ((ret = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT, &g_pcm_handle_c, &g_audio_manager_handle_c, (char*) "voice", SND_PCM_OPEN_CAPTURE)) < 0) { return; } snd_pcm_plugin_set_disable(g_pcm_handle_c, PLUGIN_DISABLE_MMAP); snd_pcm_plugin_set_enable(g_pcm_handle_c, PLUGIN_ROUTING); // sample reads the capabilities of the capture memset(&pi, 0, sizeof(pi)); pi.channel = SND_PCM_CHANNEL_CAPTURE; if ((ret = snd_pcm_plugin_info(g_pcm_handle_c, &pi)) < 0) { fprintf(stderr, "snd_pcm_plugin_info failed: %s\n", snd_strerror (ret)); return; } fprintf(stderr,"CAPTURE Minimum Rate = %d\n",pi.min_rate); // Request the VoIP parameters // These parameters are different to waverec sample memset(&pp, 0, sizeof(pp)); fprintf(stderr,"CAPTURE Minimum fragment size = %d\n",pi.min_fragment_size); // Blocking read pp.mode = SND_PCM_MODE_BLOCK; pp.channel = SND_PCM_CHANNEL_CAPTURE; //pp.start_mode = SND_PCM_START_DATA; // Auto-recover from errors pp.stop_mode = SND_PCM_STOP_ROLLOVER; pp.start_mode = SND_PCM_START_DATA; pp.buf.block.frag_size = PREFERRED_FRAME_SIZE; pp.buf.block.frags_max = 3; pp.buf.block.frags_min = 1; pp.format.interleave = 1; pp.format.rate = VOIP_SAMPLE_RATE; pp.format.voices = 1; pp.format.format = SND_PCM_SFMT_S16_LE; // make the request if ((ret = snd_pcm_plugin_params(g_pcm_handle_c, &pp)) < 0) { fprintf(stderr, "ca snd_pcm_plugin_params failed: %s\n", snd_strerror (ret)); return; } // Again based on the sample memset(&setup, 0, sizeof(setup)); memset(&group, 0, sizeof(group)); setup.channel = SND_PCM_CHANNEL_CAPTURE; setup.mixer_gid = &group.gid; if ((ret = snd_pcm_plugin_setup(g_pcm_handle_c, &setup)) < 0) { fprintf(stderr, "snd_pcm_plugin_setup failed: %s\n", snd_strerror (ret)); return; } // On the simulator at least, our requested capabilities are accepted. fprintf(stderr,"CAPTURE Format %s card = %d\n", snd_pcm_get_format_name (setup.format.format),card); fprintf(stderr,"CAPTURE Rate %d \n", setup.format.rate); g_frame_size_c = setup.buf.block.frag_size; if (group.gid.name[0] == 0) { printf("Mixer Pcm Group [%s] Not Set \n", group.gid.name); printf("***>>>> Input Gain Controls Disabled <<<<*** \n"); } else { printf("Mixer Pcm Group [%s]\n", group.gid.name); } g_frame_size_c = setup.buf.block.frag_size; fprintf(stderr, "CAPTURE frame_size = %d\n", g_frame_size_c); // Sample calls prepare() if ((ret = snd_pcm_plugin_prepare(g_pcm_handle_c, SND_PCM_CHANNEL_CAPTURE)) < 0) { fprintf(stderr, "snd_pcm_plugin_prepare failed: %s\n", snd_strerror (ret)); } }
static pj_status_t bb10_open_capture (struct bb10_stream *stream, const pjmedia_aud_param *param) { int ret = 0; unsigned int rate; unsigned long tmp_buf_size; int card = -1; int dev = 0; int frame_size; snd_pcm_channel_info_t pi; snd_mixer_group_t group; snd_pcm_channel_params_t pp; snd_pcm_channel_setup_t setup; unsigned int handle; if (param->rec_id < 0 || param->rec_id >= stream->af->dev_cnt) return PJMEDIA_EAUD_INVDEV; #if PJ_BBSDK_VER >= 0x100006 if ((ret = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VOICE, &stream->ca_pcm, &handle, "/dev/snd/voicec", SND_PCM_OPEN_CAPTURE)) < 0) { TRACE_((THIS_FILE, "audio_manager_snd_pcm_open_name ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } #else /* BB10 Audio init here (not prepare) */ PJ_UNUSED_ARG(handle); if ((ret = snd_pcm_open_preferred (&stream->ca_pcm, &card, &dev, SND_PCM_OPEN_CAPTURE)) < 0) { TRACE_((THIS_FILE, "snd_pcm_open_preferred ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } #endif /* sample reads the capabilities of the capture */ memset (&pi, 0, sizeof (pi)); pi.channel = SND_PCM_CHANNEL_CAPTURE; if ((ret = snd_pcm_plugin_info (stream->ca_pcm, &pi)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_info ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } /* Request the VoIP parameters * These parameters are different to waverec sample */ memset (&pp, 0, sizeof (pp)); /* Blocking read */ pp.mode = SND_PCM_MODE_BLOCK; pp.channel = SND_PCM_CHANNEL_CAPTURE; pp.start_mode = SND_PCM_START_DATA; /* Auto-recover from errors */ pp.stop_mode = SND_PCM_STOP_ROLLOVER; /* HARD CODE for the time being PJMEDIA expects 640 for 16khz */ pp.buf.block.frag_size = PREFERRED_FRAME_SIZE*2; /* Not applicable for capture hence -1 */ pp.buf.block.frags_max = -1; pp.buf.block.frags_min = 1; pp.format.interleave = 1; /* HARD CODE for the time being PJMEDIA expects 16khz */ PJ_TODO(REMOVE_SAMPLE_RATE_HARD_CODE); pj_assert(param->clock_rate == VOIP_SAMPLE_RATE * 2); pp.format.rate = VOIP_SAMPLE_RATE*2; pp.format.voices = 1; pp.format.format = SND_PCM_SFMT_S16_LE; /* make the request */ if ((ret = snd_pcm_plugin_params (stream->ca_pcm, &pp)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_params ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } /* Again based on the sample */ memset (&setup, 0, sizeof (setup)); memset (&group, 0, sizeof (group)); setup.channel = SND_PCM_CHANNEL_CAPTURE; setup.mixer_gid = &group.gid; if ((ret = snd_pcm_plugin_setup (stream->ca_pcm, &setup)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_setup ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } frame_size = setup.buf.block.frag_size; if (group.gid.name[0] == 0) { } else { } /* frag_size should be 160 */ frame_size = setup.buf.block.frag_size; /* END BB10 init */ /* Set clock rate */ rate = param->clock_rate; stream->ca_frames = (unsigned long) param->samples_per_frame / param->channel_count; /* Set the sound device buffer size and latency */ if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY) { tmp_buf_size = (rate / 1000) * param->input_latency_ms; } else { tmp_buf_size = (rate / 1000) * PJMEDIA_SND_DEFAULT_REC_LATENCY; } stream->param.input_latency_ms = tmp_buf_size / (rate / 1000); /* Set our buffer */ stream->ca_buf_size = stream->ca_frames * param->channel_count * (param->bits_per_sample/8); stream->ca_buf = (char *)pj_pool_alloc (stream->pool, stream->ca_buf_size); TRACE_((THIS_FILE, "bb10_open_capture: ca_frames = %d clock = %d", stream->ca_frames, param->clock_rate)); return PJ_SUCCESS; }
static pj_status_t bb10_open_playback (struct bb10_stream *stream, const pjmedia_aud_param *param) { int card = -1; int dev = 0; int ret = 0; snd_pcm_channel_info_t pi; snd_pcm_channel_setup_t setup; snd_mixer_group_t group; snd_pcm_channel_params_t pp; unsigned int rate; unsigned long tmp_buf_size; unsigned int handle; if (param->play_id < 0 || param->play_id >= stream->af->dev_cnt) { return PJMEDIA_EAUD_INVDEV; } #if PJ_BBSDK_VER >= 0x100006 if ((ret = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VOICE, &stream->pb_pcm, &handle, "/dev/snd/voicep", SND_PCM_OPEN_PLAYBACK)) < 0) { TRACE_((THIS_FILE, "audio_manager_snd_pcm_open_name ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } #else if ((ret = snd_pcm_open_preferred (&stream->pb_pcm, &card, &dev, SND_PCM_OPEN_PLAYBACK)) < 0) { TRACE_((THIS_FILE, "snd_pcm_open_preferred ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } #endif /* TODO PJ_ZERO */ memset (&pi, 0, sizeof (pi)); pi.channel = SND_PCM_CHANNEL_PLAYBACK; if ((ret = snd_pcm_plugin_info (stream->pb_pcm, &pi)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_info ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } memset (&pp, 0, sizeof (pp)); /* Request VoIP compatible capabilities * On simulator frag_size is always negotiated to 170 */ pp.mode = SND_PCM_MODE_BLOCK; pp.channel = SND_PCM_CHANNEL_PLAYBACK; pp.start_mode = SND_PCM_START_DATA; pp.stop_mode = SND_PCM_STOP_ROLLOVER; /* HARD CODE for the time being PJMEDIA expects 640 for 16khz */ pp.buf.block.frag_size = PREFERRED_FRAME_SIZE*2; /* Increasing this internal buffer count delays write failure in the loop */ pp.buf.block.frags_max = 4; pp.buf.block.frags_min = 1; pp.format.interleave = 1; /* HARD CODE for the time being PJMEDIA expects 16khz */ PJ_TODO(REMOVE_SAMPLE_RATE_HARD_CODE); pj_assert(param->clock_rate == VOIP_SAMPLE_RATE * 2); pp.format.rate = VOIP_SAMPLE_RATE*2; pp.format.voices = 1; pp.format.format = SND_PCM_SFMT_S16_LE; /* Make the calls as per the wave sample */ if ((ret = snd_pcm_plugin_params (stream->pb_pcm, &pp)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_params ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } memset (&setup, 0, sizeof (setup)); memset (&group, 0, sizeof (group)); setup.channel = SND_PCM_CHANNEL_PLAYBACK; setup.mixer_gid = &group.gid; if ((ret = snd_pcm_plugin_setup (stream->pb_pcm, &setup)) < 0) { TRACE_((THIS_FILE, "snd_pcm_plugin_setup ret = %d", ret)); return PJMEDIA_EAUD_SYSERR; } if (group.gid.name[0] == 0) { return PJMEDIA_EAUD_SYSERR; } rate = param->clock_rate; /* Set the sound device buffer size and latency */ if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY) { tmp_buf_size = (rate / 1000) * param->output_latency_ms; } else { tmp_buf_size = (rate / 1000) * PJMEDIA_SND_DEFAULT_PLAY_LATENCY; } /* Set period size to samples_per_frame frames. */ stream->pb_frames = param->samples_per_frame; stream->param.output_latency_ms = tmp_buf_size / (rate / 1000); /* Set our buffer */ stream->pb_buf_size = stream->pb_frames * param->channel_count * (param->bits_per_sample/8); stream->pb_buf = (char *) pj_pool_alloc(stream->pool, stream->pb_buf_size); TRACE_((THIS_FILE, "bb10_open_playback: pb_frames = %d clock = %d", stream->pb_frames, param->clock_rate)); return PJ_SUCCESS; }