summaryrefslogtreecommitdiff
path: root/pjmedia/src/pjmedia-audiodev/bb10_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjmedia/src/pjmedia-audiodev/bb10_dev.c')
-rw-r--r--pjmedia/src/pjmedia-audiodev/bb10_dev.c364
1 files changed, 269 insertions, 95 deletions
diff --git a/pjmedia/src/pjmedia-audiodev/bb10_dev.c b/pjmedia/src/pjmedia-audiodev/bb10_dev.c
index 418256d..f920080 100644
--- a/pjmedia/src/pjmedia-audiodev/bb10_dev.c
+++ b/pjmedia/src/pjmedia-audiodev/bb10_dev.c
@@ -1,4 +1,4 @@
-/* $Id: bb10_dev.c 4151 2012-06-01 04:49:57Z ming $ */
+/* $Id: bb10_dev.c 4340 2013-02-05 05:15:01Z bennylp $ */
/*
* Copyright (C) 2008-2012 Teluu Inc. (http://www.teluu.com)
*
@@ -33,6 +33,11 @@
#if defined(PJMEDIA_AUDIO_DEV_HAS_BB10) && PJMEDIA_AUDIO_DEV_HAS_BB10 != 0
+#ifndef PJ_BBSDK_VER
+ /* Format: 0xMMNNRR: MM: major, NN: minor, RR: revision */
+# define PJ_BBSDK_VER 0x100006
+#endif
+
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
@@ -40,6 +45,9 @@
#include <pthread.h>
#include <errno.h>
#include <sys/asoundlib.h>
+#if PJ_BBSDK_VER >= 0x100006
+#include <audio/audio_manager_routing.h>
+#endif
#define THIS_FILE "bb10_dev.c"
@@ -114,8 +122,9 @@ struct bb10_stream
int quit;
/* Playback */
+ unsigned int pb_ctrl_audio_manager_handle;
snd_pcm_t *pb_pcm;
- snd_mixer_t *pb_mixer;
+ unsigned int pb_audio_manager_handle;
unsigned long pb_frames; /* samples_per_frame */
pjmedia_aud_play_cb pb_cb;
unsigned pb_buf_size;
@@ -124,7 +133,7 @@ struct bb10_stream
/* Capture */
snd_pcm_t *ca_pcm;
- snd_mixer_t *ca_mixer;
+ unsigned int ca_audio_manager_handle;
unsigned long ca_frames; /* samples_per_frame */
pjmedia_aud_rec_cb ca_cb;
unsigned ca_buf_size;
@@ -160,8 +169,7 @@ static pj_status_t bb10_add_dev (struct bb10_factory *af)
{
pjmedia_aud_dev_info *adi;
int pb_result, ca_result;
- int card = -1;
- int dev = 0;
+ unsigned int handle;
snd_pcm_t *pcm_handle;
if (af->dev_cnt >= PJ_ARRAY_SIZE(af->devs))
@@ -171,20 +179,29 @@ static pj_status_t bb10_add_dev (struct bb10_factory *af)
TRACE_((THIS_FILE, "bb10_add_dev Enter"));
- if ((pb_result = snd_pcm_open_preferred (&pcm_handle, &card, &dev,
- SND_PCM_OPEN_PLAYBACK)) >= 0)
+ if ((pb_result = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT,
+ &pcm_handle,
+ &handle,
+ (char*)"voice",
+ SND_PCM_OPEN_PLAYBACK))
+ >= 0)
{
- TRACE_((THIS_FILE, "Try to open the device for playback - success"));
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 = snd_pcm_open_preferred (&pcm_handle, &card, &dev,
- SND_PCM_OPEN_CAPTURE)) >=0)
+ if ((ca_result = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT,
+ &pcm_handle,
+ &handle,
+ (char*)"voice",
+ SND_PCM_OPEN_CAPTURE))
+ >= 0)
{
- TRACE_((THIS_FILE, "Try to open the device for capture - success"));
- snd_pcm_close (pcm_handle);
+ snd_pcm_close (pcm_handle);
+ audio_manager_free_handle(handle);
+
} else {
TRACE_((THIS_FILE, "Try to open the device for capture - failure"));
}
@@ -239,7 +256,7 @@ pjmedia_aud_dev_factory* pjmedia_bb10_factory(pj_pool_factory *pf)
static pj_status_t bb10_factory_init(pjmedia_aud_dev_factory *f)
{
pj_status_t status;
-
+
status = bb10_factory_refresh(f);
if (status != PJ_SUCCESS)
return status;
@@ -314,7 +331,7 @@ static pj_status_t bb10_factory_get_dev_info(pjmedia_aud_dev_factory *f,
pj_memcpy(info, &af->devs[index], sizeof(*info));
info->caps = PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY |
PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
-
+
return PJ_SUCCESS;
}
@@ -358,7 +375,7 @@ static pj_status_t bb10_factory_default_param(pjmedia_aud_dev_factory *f,
TRACE_((THIS_FILE, "bb10_factory_default_param clock = %d flags = %d"
" spf = %d", param->clock_rate, param->flags,
param->samples_per_frame));
-
+
return PJ_SUCCESS;
}
@@ -368,14 +385,16 @@ static void close_play_pcm(struct bb10_stream *stream)
if (stream != NULL && stream->pb_pcm != NULL) {
snd_pcm_close(stream->pb_pcm);
stream->pb_pcm = NULL;
- }
-}
-static void close_play_mixer(struct bb10_stream *stream)
-{
- if (stream != NULL && stream->pb_mixer != NULL) {
- snd_mixer_close(stream->pb_mixer);
- stream->pb_mixer = NULL;
+ if (stream->pb_audio_manager_handle != 0) {
+ audio_manager_free_handle(stream->pb_audio_manager_handle);
+ stream->pb_audio_manager_handle = 0;
+ }
+
+ if (stream->pb_ctrl_audio_manager_handle != 0) {
+ audio_manager_free_handle(stream->pb_ctrl_audio_manager_handle);
+ stream->pb_ctrl_audio_manager_handle = 0;
+ }
}
}
@@ -391,14 +410,11 @@ static void close_capture_pcm(struct bb10_stream *stream)
if (stream != NULL && stream->ca_pcm != NULL) {
snd_pcm_close(stream->ca_pcm);
stream->ca_pcm = NULL;
- }
-}
-static void close_capture_mixer(struct bb10_stream *stream)
-{
- if (stream != NULL && stream->ca_mixer != NULL) {
- snd_mixer_close(stream->ca_mixer);
- stream->ca_mixer = NULL;
+ if (stream->ca_audio_manager_handle != 0) {
+ audio_manager_free_handle(stream->ca_audio_manager_handle);
+ stream->ca_audio_manager_handle = 0;
+ }
}
}
@@ -435,10 +451,9 @@ static int pb_thread_func (void *arg)
if ((result = snd_pcm_plugin_prepare(stream->pb_pcm,
SND_PCM_CHANNEL_PLAYBACK)) < 0)
{
- close_play_mixer(stream);
close_play_pcm(stream);
TRACE_((THIS_FILE, "pb_thread_func failed prepare = %d", result));
- return PJ_SUCCESS;
+ return PJ_SUCCESS;
}
while (!stream->quit) {
@@ -451,6 +466,7 @@ static int pb_thread_func (void *arg)
frame.timestamp.u64 = tstamp.u64;
frame.bit_info = 0;
+ /* Read the audio from pjmedia */
result = stream->pb_cb (user_data, &frame);
if (result != PJ_SUCCESS || stream->quit)
break;
@@ -460,18 +476,45 @@ static int pb_thread_func (void *arg)
/* Write 640 to play unit */
result = snd_pcm_plugin_write(stream->pb_pcm,buf,size);
- if (result != size) {
- TRACE_((THIS_FILE, "pb_thread_func failed write = %d", result));
+ if (result != size || result < 0) {
+ /* either the write to output device has failed or not the
+ * full amount of bytes have been written. This usually happens
+ * when audio routing is being changed by another thread
+ * Use a status variable for reading the error
+ */
+ snd_pcm_channel_status_t status;
+ status.channel = SND_PCM_CHANNEL_PLAYBACK;
+ if (snd_pcm_plugin_status (stream->pb_pcm, &status) < 0) {
+ /* Call has failed nothing we can do except log and
+ * continue */
+ PJ_LOG(4,(THIS_FILE,
+ "underrun: playback channel status error"));
+ } else {
+ /* The status of the error has been read
+ * RIM say these are expected so we can "re-prepare" the stream
+ */
+ PJ_LOG(4,(THIS_FILE,"PLAY thread ERROR status = %d",
+ status.status));
+ if (status.status == SND_PCM_STATUS_READY ||
+ status.status == SND_PCM_STATUS_UNDERRUN ||
+ status.status == SND_PCM_STATUS_ERROR )
+ {
+ if (snd_pcm_plugin_prepare (stream->pb_pcm,
+ SND_PCM_CHANNEL_PLAYBACK) < 0)
+ {
+ PJ_LOG(4,(THIS_FILE,
+ "underrun: playback channel prepare error"));
+ }
+ }
+ }
}
-
tstamp.u64 += nframes;
}
flush_play(stream);
- close_play_mixer(stream);
close_play_pcm(stream);
TRACE_((THIS_FILE, "pb_thread_func: Stopped"));
-
+
return PJ_SUCCESS;
}
@@ -513,29 +556,58 @@ static int ca_thread_func (void *arg)
if ((result = snd_pcm_plugin_prepare (stream->ca_pcm,
SND_PCM_CHANNEL_CAPTURE)) < 0)
{
- close_capture_mixer(stream);
close_capture_pcm(stream);
TRACE_((THIS_FILE, "ca_thread_func failed prepare = %d", result));
- return PJ_SUCCESS;
+ return PJ_SUCCESS;
}
while (!stream->quit) {
pjmedia_frame frame;
pj_bzero (buf, size);
-
+
+ /* read the input device */
result = snd_pcm_plugin_read(stream->ca_pcm, buf,size);
- if (result == -EPIPE) {
- PJ_LOG (4,(THIS_FILE, "ca_thread_func: overrun!"));
- snd_pcm_plugin_prepare (stream->ca_pcm, SND_PCM_CHANNEL_CAPTURE);
- continue;
- } else if (result < 0) {
- PJ_LOG (4,(THIS_FILE, "ca_thread_func: error reading data!"));
+ if(result <0 || result != size) {
+ /* We expect result to be size (640)
+ * It's not so we have to read the status error and "prepare"
+ * the channel. This usually happens when output audio routing
+ * has been changed by another thread.
+ * We won't "continue", instead just do what we can and leave
+ * the end of the loop to write what's in the buffer. Not entirely
+ * correct but saves a potential underrun in PJMEDIA
+ */
+ PJ_LOG (4,(THIS_FILE,
+ "snd_pcm_plugin_read ERROR read = %d required = %d",
+ result,size));
+ snd_pcm_channel_status_t status;
+ status.channel = SND_PCM_CHANNEL_CAPTURE;
+ if ((result = snd_pcm_plugin_status (stream->ca_pcm, &status)) < 0)
+ {
+ /* Should not fail but all we can do is continue */
+ PJ_LOG(4,(THIS_FILE, "capture: snd_pcm_plugin_status ret = %d",
+ result));
+ } else {
+ /* RIM say these are the errors that we should "prepare"
+ * after */
+ if (status.status == SND_PCM_STATUS_READY ||
+ status.status == SND_PCM_STATUS_OVERRUN ||
+ status.status == SND_PCM_STATUS_ERROR)
+ {
+ if (snd_pcm_plugin_prepare (stream->ca_pcm,
+ SND_PCM_CHANNEL_CAPTURE) < 0)
+ {
+ PJ_LOG (4,(THIS_FILE,
+ "overrun: capture channel prepare error"));
+ }
+ }
+ }
}
if (stream->quit)
break;
+ /* Write the capture audio data to PJMEDIA */
frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
frame.buf = (void *) buf;
frame.size = size;
@@ -550,19 +622,68 @@ static int ca_thread_func (void *arg)
}
flush_capture(stream);
- close_capture_mixer(stream);
close_capture_pcm(stream);
TRACE_((THIS_FILE, "ca_thread_func: Stopped"));
return PJ_SUCCESS;
}
+/* Audio routing, speaker/headset */
+static pj_status_t bb10_initialize_playback_ctrl(struct bb10_stream *stream,
+ bool speaker)
+{
+ /* Although the play and capture have audio manager handles, audio routing
+ * requires a separate handle
+ */
+ int ret = PJ_SUCCESS;
+
+ if (stream->pb_ctrl_audio_manager_handle == 0) {
+ /* lazy init an audio manager handle */
+ ret = audio_manager_get_handle(AUDIO_TYPE_VIDEO_CHAT, 0, false,
+ &stream->pb_ctrl_audio_manager_handle);
+ if (ret != 0) {
+ TRACE_((THIS_FILE, "audio_manager_get_handle ret = %d",ret));
+ return PJMEDIA_EAUD_SYSERR;
+ }
+ }
+
+ /* Set for either speaker or earpiece */
+ if (speaker) {
+ ret = audio_manager_set_handle_type(
+ stream->pb_ctrl_audio_manager_handle,
+ AUDIO_TYPE_VIDEO_CHAT,
+ AUDIO_DEVICE_SPEAKER,
+ AUDIO_DEVICE_DEFAULT);
+ } else {
+ ret = audio_manager_set_handle_type(
+ stream->pb_ctrl_audio_manager_handle,
+ AUDIO_TYPE_VIDEO_CHAT,
+ AUDIO_DEVICE_HANDSET,
+ AUDIO_DEVICE_DEFAULT);
+ }
+
+ if (ret == 0) {
+ /* RIM recommend this call */
+ ret = audio_manager_set_handle_routing_conditions(
+ stream->pb_ctrl_audio_manager_handle,
+ SETTINGS_RESET_ON_DEVICE_CONNECTION);
+ if (ret != 0) {
+ TRACE_((THIS_FILE,
+ "audio_manager_set_handle_routing_conditions ret = %d",
+ ret));
+ return PJMEDIA_EAUD_SYSERR;
+ }
+ } else {
+ TRACE_((THIS_FILE, "audio_manager_set_handle_type ret = %d", ret));
+ return PJMEDIA_EAUD_SYSERR;
+ }
+
+ 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;
@@ -575,34 +696,54 @@ static pj_status_t bb10_open_playback (struct bb10_stream *stream,
return PJMEDIA_EAUD_INVDEV;
}
- if ((ret = snd_pcm_open_preferred (&stream->pb_pcm, &card, &dev,
- SND_PCM_OPEN_PLAYBACK)) < 0)
+ /* 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, "snd_pcm_open_preferred ret = %d", ret));
+ TRACE_((THIS_FILE, "audio_manager_snd_pcm_open_name ret = %d", ret));
return PJMEDIA_EAUD_SYSERR;
}
+ /* Required call from January 2013 gold OS release */
+ if ((ret = snd_pcm_plugin_set_disable(stream->pb_pcm,
+ PLUGIN_DISABLE_MMAP)) < 0)
+ {
+ TRACE_((THIS_FILE, "snd_pcm_plugin_set_disable ret = %d", ret));
+ return PJMEDIA_EAUD_SYSERR;
+ }
+
+ /* Required call from January 2013 gold OS release */
+ if ((ret = snd_pcm_plugin_set_enable(stream->pb_pcm,
+ PLUGIN_ROUTING)) < 0)
+ {
+ TRACE_((THIS_FILE, "snd_pcm_plugin_set_enable ret = %d", ret));
+ return PJMEDIA_EAUD_SYSERR;
+ }
+
/* 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;
+ 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
- */
+ /* Request VoIP compatible capabilities */
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;
+ /* RIM recommends maximum of 3 */
+ pp.buf.block.frags_max = 3;
pp.buf.block.frags_min = 1;
pp.format.interleave = 1;
/* HARD CODE for the time being PJMEDIA expects 16khz */
@@ -622,7 +763,7 @@ static pj_status_t bb10_open_playback (struct bb10_stream *stream,
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;
@@ -631,14 +772,6 @@ static pj_status_t bb10_open_playback (struct bb10_stream *stream,
if (group.gid.name[0] == 0) {
return PJMEDIA_EAUD_SYSERR;
}
-
- if ((ret = snd_mixer_open (&stream->pb_mixer, card,
- setup.mixer_device)) < 0)
- {
- TRACE_((THIS_FILE, "snd_mixer_open ret = %d", ret));
- return PJMEDIA_EAUD_SYSERR;
- }
-
rate = param->clock_rate;
/* Set the sound device buffer size and latency */
@@ -658,7 +791,7 @@ static pj_status_t bb10_open_playback (struct bb10_stream *stream,
TRACE_((THIS_FILE, "bb10_open_playback: pb_frames = %d clock = %d",
stream->pb_frames, param->clock_rate));
-
+
return PJ_SUCCESS;
}
@@ -668,8 +801,6 @@ static pj_status_t bb10_open_capture (struct bb10_stream *stream,
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;
@@ -679,11 +810,27 @@ static pj_status_t bb10_open_capture (struct bb10_stream *stream,
if (param->rec_id < 0 || param->rec_id >= stream->af->dev_cnt)
return PJMEDIA_EAUD_INVDEV;
- /* BB10 Audio init here (not prepare) */
- if ((ret = snd_pcm_open_preferred (&stream->ca_pcm, &card, &dev,
- SND_PCM_OPEN_CAPTURE)) < 0)
+ 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 */
+ if ((ret = snd_pcm_plugin_set_disable (stream->ca_pcm,
+ PLUGIN_DISABLE_MMAP)) < 0)
{
- TRACE_((THIS_FILE, "snd_pcm_open_preferred ret = %d", ret));
+ TRACE_(("snd_pcm_plugin_set_disable failed: %d",ret));
+ return PJMEDIA_EAUD_SYSERR;
+ }
+ /* Required call from January 2013 gold OS release */
+ if ((ret = snd_pcm_plugin_set_enable(stream->ca_pcm,
+ PLUGIN_ROUTING)) < 0)
+ {
+ TRACE_(("snd_pcm_plugin_set_enable failed: %d",ret));
return PJMEDIA_EAUD_SYSERR;
}
@@ -707,8 +854,8 @@ static pj_status_t bb10_open_capture (struct bb10_stream *stream,
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;
+ /* From January 2013 gold OS release. RIM recommend these for capture */
+ 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 */
@@ -740,18 +887,8 @@ static pj_status_t bb10_open_capture (struct bb10_stream *stream,
} else {
}
- if ((ret = snd_mixer_open (&stream->ca_mixer, card,
- setup.mixer_device)) < 0)
- {
- TRACE_((THIS_FILE,"snd_mixer_open ret = %d",ret));
- return PJMEDIA_EAUD_SYSERR;
- }
-
- /* 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 /
@@ -820,7 +957,6 @@ static pj_status_t bb10_factory_create_stream(pjmedia_aud_dev_factory *f,
status = bb10_open_capture (stream, param);
if (status != PJ_SUCCESS) {
if (param->dir & PJMEDIA_DIR_PLAYBACK) {
- close_play_mixer(stream);
close_play_pcm(stream);
}
pj_pool_release (pool);
@@ -828,12 +964,24 @@ static pj_status_t bb10_factory_create_stream(pjmedia_aud_dev_factory *f,
}
}
+ /* Part of the play functionality but the RIM/Truphone loopback sample
+ * initialializes after the play and capture
+ * "false" is default/earpiece for output
+ */
+ status = bb10_initialize_playback_ctrl(stream,false);
+ if (status != PJ_SUCCESS) {
+ return PJMEDIA_EAUD_SYSERR;
+ }
+
*p_strm = &stream->base;
return PJ_SUCCESS;
}
-/* API: get running parameter */
+/*
+ * API: get running parameter
+ * based on ALSA template
+ */
static pj_status_t bb10_stream_get_param(pjmedia_aud_stream *s,
pjmedia_aud_param *pi)
{
@@ -847,7 +995,10 @@ static pj_status_t bb10_stream_get_param(pjmedia_aud_stream *s,
}
-/* API: get capability */
+/*
+ * API: get capability
+ * based on ALSA template
+*/
static pj_status_t bb10_stream_get_cap(pjmedia_aud_stream *s,
pjmedia_aud_dev_cap cap,
void *pval)
@@ -862,28 +1013,51 @@ static pj_status_t bb10_stream_get_cap(pjmedia_aud_stream *s,
/* Recording latency */
*(unsigned*)pval = stream->param.input_latency_ms;
return PJ_SUCCESS;
+
} else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY &&
(stream->param.dir & PJMEDIA_DIR_PLAYBACK))
{
/* Playback latency */
*(unsigned*)pval = stream->param.output_latency_ms;
return PJ_SUCCESS;
+
} else {
return PJMEDIA_EAUD_INVCAP;
}
}
-/* API: set capability */
+/*
+ * API: set capability
+ * Currently just supporting toggle between speaker and earpiece
+ */
static pj_status_t bb10_stream_set_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
const void *value)
{
- PJ_UNUSED_ARG(strm);
- PJ_UNUSED_ARG(cap);
- PJ_UNUSED_ARG(value);
+ pj_status_t ret = PJ_SUCCESS;
+ struct bb10_stream *stream = (struct bb10_stream*)strm;
+
+ if (cap != PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE || value == NULL) {
+ TRACE_((THIS_FILE,"bb10_stream_set_cap() = PJMEDIA_EAUD_INVCAP"));
+ return PJMEDIA_EAUD_INVCAP;
+
+ } else {
+ pjmedia_aud_dev_route route = *((pjmedia_aud_dev_route*)value);
+ /* Use the initialization function which lazy-inits the
+ * handle for routing
+ */
+ if (route == PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER) {
+ ret = bb10_initialize_playback_ctrl(stream,true);
+ } else {
+ ret = bb10_initialize_playback_ctrl(stream,false);
+ }
+ }
- return PJMEDIA_EAUD_INVCAP;
+ if (ret != PJ_SUCCESS) {
+ TRACE_((THIS_FILE,"bb10_stream_set_cap() = %d",ret));
+ }
+ return ret;
}
@@ -952,7 +1126,7 @@ static pj_status_t bb10_stream_stop (pjmedia_aud_stream *s)
static pj_status_t bb10_stream_destroy (pjmedia_aud_stream *s)
{
struct bb10_stream *stream = (struct bb10_stream*)s;
-
+
TRACE_((THIS_FILE,"bb10_stream_destroy()"));
bb10_stream_stop (s);