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; }
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 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 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)); } }
// Initialize audio and report back a few parameters of the channel int setupAudio( ) { int error; snd_pcm_channel_info_t pi; snd_pcm_channel_params_t pp; snd_pcm_channel_setup_t ps; //if ((error = snd_pcm_open_name (&playback_handle, "pcmPreferred", SND_PCM_OPEN_PLAYBACK)) < 0) { if ((error = snd_pcm_open_name (&playback_handle, "tones", SND_PCM_OPEN_PLAYBACK)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to open preferred audio driver\n"); return -error; } sample_handle = snd_pcm_file_descriptor( playback_handle, SND_PCM_CHANNEL_PLAYBACK ); if ((error = snd_pcm_plugin_set_disable (playback_handle, PLUGIN_DISABLE_MMAP)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to disable mmap\n"); snd_pcm_close(playback_handle); return -error; } if ((error = snd_pcm_plugin_set_enable (playback_handle, PLUGIN_ROUTING)) < 0) { slogf ( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "snd_pcm_plugin_set_enable failed: %s\n", snd_strerror (error)); snd_pcm_close(playback_handle); return -error; } // Find what sample rate and format to use memset( &pi, 0, sizeof(pi) ); pi.channel = SND_PCM_CHANNEL_PLAYBACK; if ((error = snd_pcm_channel_info (playback_handle, &pi)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to get plugin info\n"); snd_pcm_close(playback_handle); return -error; } // Initialize the playback channel memset(&pp, 0, sizeof(pp) ); 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_STOP; pp.buf.block.frag_size = pi.max_fragment_size; pp.buf.block.frags_max = 3; pp.buf.block.frags_min = 1; pp.format.interleave = 1; pp.format.format = SND_PCM_SFMT_S16_LE; pp.format.rate = 48000; pp.format.voices = 2; memset( &ps, 0, sizeof( ps ) ); memset( &group, 0, sizeof( group ) ); ps.channel = SND_PCM_CHANNEL_PLAYBACK; ps.mixer_gid = &group.gid; //strcpy(pp.sw_mixer_subchn_name, "Wave playback channel"); strcpy(pp.sw_mixer_subchn_name, "voice_ringtone"); if ((error = snd_pcm_plugin_params( playback_handle, &pp)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to set plugin params\n"); snd_pcm_close(playback_handle); return -error; } if ((error = snd_pcm_plugin_prepare (playback_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to set prepare plugin\n"); snd_pcm_close(playback_handle); return -error; } if ((error = snd_pcm_plugin_setup (playback_handle, &ps)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to setup plugin\n"); snd_pcm_close(playback_handle); return -error; } card = ps.mixer_card; device = ps.mixer_device; if( audioman_handle ) { if ((error = snd_pcm_set_audioman_handle (playback_handle, audioman_handle)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to set audioman handle \n"); snd_pcm_close(playback_handle); return -error; } } sample_frequency = ps.format.rate; frag_samples = ps.buf.block.frag_size / 4; frame_size = ps.buf.block.frag_size; format = pp.format.format; /* // Only support 16-bit samples for now frag_buffer = malloc( ps.buf.block.frag_size * 2 ); if( frag_buffer == NULL ) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to alloc frag buffer\n"); snd_pcm_close(playback_handle); return ENOMEM; } */ fprintf (stderr,"Playback Format %s card = %d\n", snd_pcm_get_format_name (ps.format.format),card); fprintf (stderr,"Playback preferred frame_size %d \n", pi.max_fragment_size); fprintf (stderr,"Playback frame_size %d \n", ps.buf.block.frag_size); fprintf (stderr,"Playback frame_samples %d \n", frag_samples); fprintf (stderr,"Playback Rate %d \n", ps.format.rate); if (group.gid.name[0] == 0) { fprintf (stderr,"Playback Mixer Pcm Group [%s] Not Set \n", group.gid.name); return -1; } fprintf (stderr, "Playback Mixer Pcm Group [%s]\n", group.gid.name); return EOK; }