| 1 | --- a/pjsip/include/pjsua-lib/pjsua.h |
| 2 | +++ b/pjsip/include/pjsua-lib/pjsua.h |
| 3 | @@ -1543,6 +1543,8 @@ PJ_DECL(pjmedia_endpt*) pjsua_get_pjmedi |
| 4 | PJ_DECL(pj_pool_factory*) pjsua_get_pool_factory(void); |
| 5 | |
| 6 | |
| 7 | +PJ_DECL(pj_status_t) pjsua_add_snd_port(int id, pjsua_conf_port_id *p_id); |
| 8 | + |
| 9 | |
| 10 | /***************************************************************************** |
| 11 | * Utilities. |
| 12 | --- a/pjsip/include/pjsua-lib/pjsua_internal.h |
| 13 | +++ b/pjsip/include/pjsua-lib/pjsua_internal.h |
| 14 | @@ -261,6 +261,8 @@ typedef struct pjsua_stun_resolve |
| 15 | } pjsua_stun_resolve; |
| 16 | |
| 17 | |
| 18 | +#define MAX_PORT 2 |
| 19 | + |
| 20 | /** |
| 21 | * Global pjsua application data. |
| 22 | */ |
| 23 | @@ -336,7 +338,7 @@ struct pjsua_data |
| 24 | pj_bool_t aud_open_cnt;/**< How many # device is opened */ |
| 25 | pj_bool_t no_snd; /**< No sound (app will manage it) */ |
| 26 | pj_pool_t *snd_pool; /**< Sound's private pool. */ |
| 27 | - pjmedia_snd_port *snd_port; /**< Sound port. */ |
| 28 | + pjmedia_snd_port *snd_port[MAX_PORT]; /**< Sound port. */ |
| 29 | pj_timer_entry snd_idle_timer;/**< Sound device idle timer. */ |
| 30 | pjmedia_master_port *null_snd; /**< Master port for null sound. */ |
| 31 | pjmedia_port *null_port; /**< Null port. */ |
| 32 | --- a/pjsip/src/pjsua-lib/pjsua_media.c |
| 33 | +++ b/pjsip/src/pjsua-lib/pjsua_media.c |
| 34 | @@ -588,7 +588,7 @@ static void check_snd_dev_idle() |
| 35 | * It is idle when there is no port connection in the bridge and |
| 36 | * there is no active call. |
| 37 | */ |
| 38 | - if ((pjsua_var.snd_port!=NULL || pjsua_var.null_snd!=NULL) && |
| 39 | + if ((pjsua_var.snd_port[0]!=NULL || pjsua_var.null_snd!=NULL) && |
| 40 | pjsua_var.snd_idle_timer.id == PJ_FALSE && |
| 41 | pjmedia_conf_get_connect_count(pjsua_var.mconf) == 0 && |
| 42 | call_cnt == 0 && |
| 43 | @@ -2008,7 +2008,7 @@ PJ_DEF(pj_status_t) pjsua_conf_connect( |
| 44 | pj_assert(status == PJ_SUCCESS); |
| 45 | |
| 46 | /* Check if sound device is instantiated. */ |
| 47 | - need_reopen = (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && |
| 48 | + need_reopen = (pjsua_var.snd_port[0]==NULL && pjsua_var.null_snd==NULL && |
| 49 | !pjsua_var.no_snd); |
| 50 | |
| 51 | /* Check if sound device need to reopen because it needs to modify |
| 52 | @@ -2072,7 +2072,7 @@ PJ_DEF(pj_status_t) pjsua_conf_connect( |
| 53 | /* The bridge version */ |
| 54 | |
| 55 | /* Create sound port if none is instantiated */ |
| 56 | - if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && |
| 57 | + if (pjsua_var.snd_port[0]==NULL && pjsua_var.null_snd==NULL && |
| 58 | !pjsua_var.no_snd) |
| 59 | { |
| 60 | pj_status_t status; |
| 61 | @@ -2686,9 +2686,9 @@ static pj_status_t update_initial_aud_pa |
| 62 | pjmedia_aud_param param; |
| 63 | pj_status_t status; |
| 64 | |
| 65 | - PJ_ASSERT_RETURN(pjsua_var.snd_port != NULL, PJ_EBUG); |
| 66 | + PJ_ASSERT_RETURN(pjsua_var.snd_port[0] != NULL, PJ_EBUG); |
| 67 | |
| 68 | - strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); |
| 69 | + strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port[0]); |
| 70 | |
| 71 | status = pjmedia_aud_stream_get_param(strm, ¶m); |
| 72 | if (status != PJ_SUCCESS) { |
| 73 | @@ -2754,7 +2754,7 @@ static pj_status_t open_snd_dev(pjmedia_ |
| 74 | 1000 / param->base.clock_rate)); |
| 75 | |
| 76 | status = pjmedia_snd_port_create2( pjsua_var.snd_pool, |
| 77 | - param, &pjsua_var.snd_port); |
| 78 | + param, &pjsua_var.snd_port[0]); |
| 79 | if (status != PJ_SUCCESS) |
| 80 | return status; |
| 81 | |
| 82 | @@ -2812,13 +2812,13 @@ static pj_status_t open_snd_dev(pjmedia_ |
| 83 | } |
| 84 | |
| 85 | /* Connect sound port to the bridge */ |
| 86 | - status = pjmedia_snd_port_connect(pjsua_var.snd_port, |
| 87 | + status = pjmedia_snd_port_connect(pjsua_var.snd_port[0], |
| 88 | conf_port ); |
| 89 | if (status != PJ_SUCCESS) { |
| 90 | pjsua_perror(THIS_FILE, "Unable to connect conference port to " |
| 91 | "sound device", status); |
| 92 | - pjmedia_snd_port_destroy(pjsua_var.snd_port); |
| 93 | - pjsua_var.snd_port = NULL; |
| 94 | + pjmedia_snd_port_destroy(pjsua_var.snd_port[0]); |
| 95 | + pjsua_var.snd_port[0] = NULL; |
| 96 | return status; |
| 97 | } |
| 98 | |
| 99 | @@ -2833,7 +2833,7 @@ static pj_status_t open_snd_dev(pjmedia_ |
| 100 | pjmedia_aud_param si; |
| 101 | pj_str_t tmp; |
| 102 | |
| 103 | - strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); |
| 104 | + strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port[0]); |
| 105 | status = pjmedia_aud_stream_get_param(strm, &si); |
| 106 | if (status == PJ_SUCCESS) |
| 107 | status = pjmedia_aud_dev_get_info(si.rec_id, &rec_info); |
| 108 | @@ -2876,12 +2876,12 @@ static pj_status_t open_snd_dev(pjmedia_ |
| 109 | static void close_snd_dev(void) |
| 110 | { |
| 111 | /* Close sound device */ |
| 112 | - if (pjsua_var.snd_port) { |
| 113 | + if (pjsua_var.snd_port[0]) { |
| 114 | pjmedia_aud_dev_info cap_info, play_info; |
| 115 | pjmedia_aud_stream *strm; |
| 116 | pjmedia_aud_param param; |
| 117 | |
| 118 | - strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); |
| 119 | + strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port[0]); |
| 120 | pjmedia_aud_stream_get_param(strm, ¶m); |
| 121 | |
| 122 | if (pjmedia_aud_dev_get_info(param.rec_id, &cap_info) != PJ_SUCCESS) |
| 123 | @@ -2893,9 +2893,9 @@ static void close_snd_dev(void) |
| 124 | "%s sound capture device", |
| 125 | play_info.name, cap_info.name)); |
| 126 | |
| 127 | - pjmedia_snd_port_disconnect(pjsua_var.snd_port); |
| 128 | - pjmedia_snd_port_destroy(pjsua_var.snd_port); |
| 129 | - pjsua_var.snd_port = NULL; |
| 130 | + pjmedia_snd_port_disconnect(pjsua_var.snd_port[0]); |
| 131 | + pjmedia_snd_port_destroy(pjsua_var.snd_port[0]); |
| 132 | + pjsua_var.snd_port[0] = NULL; |
| 133 | } |
| 134 | |
| 135 | /* Close null sound device */ |
| 136 | @@ -2984,6 +2984,35 @@ PJ_DEF(pj_status_t) pjsua_set_snd_dev( i |
| 137 | return PJ_SUCCESS; |
| 138 | } |
| 139 | |
| 140 | +PJ_DEF(pj_status_t) pjsua_add_snd_port(int id, pjsua_conf_port_id *p_id) |
| 141 | +{ |
| 142 | + unsigned alt_cr_cnt = 1; |
| 143 | + unsigned alt_cr = 0; |
| 144 | + pj_status_t status = -1; |
| 145 | + pjmedia_snd_port_param param; |
| 146 | + unsigned samples_per_frame; |
| 147 | + pjmedia_port *port; |
| 148 | + const pj_str_t name = pj_str("tapi2"); |
| 149 | + alt_cr = pjsua_var.media_cfg.clock_rate; |
| 150 | + samples_per_frame = alt_cr * |
| 151 | + pjsua_var.media_cfg.audio_frame_ptime * |
| 152 | + pjsua_var.media_cfg.channel_count / 1000; |
| 153 | + status = create_aud_param(¶m.base, |
| 154 | + pjsua_var.play_dev, |
| 155 | + pjsua_var.cap_dev, |
| 156 | + alt_cr, |
| 157 | + pjsua_var.media_cfg.channel_count, |
| 158 | + samples_per_frame, 16); |
| 159 | + if (status != PJ_SUCCESS) |
| 160 | + return status; |
| 161 | + param.base.rec_id = id; |
| 162 | + param.base.play_id = id; |
| 163 | + param.options = 0; |
| 164 | + status = pjmedia_snd_port_create2(pjsua_var.snd_pool, |
| 165 | + ¶m, &pjsua_var.snd_port[id]); |
| 166 | + return PJ_SUCCESS; |
| 167 | +} |
| 168 | + |
| 169 | |
| 170 | /* |
| 171 | * Get currently active sound devices. If sound devices has not been created |
| 172 | @@ -3088,7 +3117,7 @@ PJ_DEF(pj_status_t) pjsua_set_ec(unsigne |
| 173 | pjsua_var.media_cfg.ec_options = options; |
| 174 | |
| 175 | if (pjsua_var.snd_port) |
| 176 | - status = pjmedia_snd_port_set_ec(pjsua_var.snd_port, pjsua_var.pool, |
| 177 | + status = pjmedia_snd_port_set_ec(pjsua_var.snd_port[0], pjsua_var.pool, |
| 178 | tail_ms, options); |
| 179 | |
| 180 | PJSUA_UNLOCK(); |
| 181 | @@ -3111,7 +3140,7 @@ PJ_DEF(pj_status_t) pjsua_get_ec_tail(un |
| 182 | */ |
| 183 | PJ_DEF(pj_bool_t) pjsua_snd_is_active(void) |
| 184 | { |
| 185 | - return pjsua_var.snd_port != NULL; |
| 186 | + return pjsua_var.snd_port[0] != NULL; |
| 187 | } |
| 188 | |
| 189 | |
| 190 | @@ -3135,7 +3164,7 @@ PJ_DEF(pj_status_t) pjsua_snd_set_settin |
| 191 | if (pjsua_snd_is_active()) { |
| 192 | pjmedia_aud_stream *strm; |
| 193 | |
| 194 | - strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); |
| 195 | + strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port[0]); |
| 196 | status = pjmedia_aud_stream_set_cap(strm, cap, pval); |
| 197 | } else { |
| 198 | status = PJ_SUCCESS; |
| 199 | @@ -3181,7 +3210,7 @@ PJ_DEF(pj_status_t) pjsua_snd_get_settin |
| 200 | /* Sound is active, retrieve from device directly */ |
| 201 | pjmedia_aud_stream *strm; |
| 202 | |
| 203 | - strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); |
| 204 | + strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port[0]); |
| 205 | status = pjmedia_aud_stream_get_cap(strm, cap, pval); |
| 206 | } else { |
| 207 | /* Otherwise retrieve from internal param */ |
| 208 | |