diff --git a/sflphone-client-gnome/pixmaps/Makefile.am b/sflphone-client-gnome/pixmaps/Makefile.am index d18c3356c6c5752f0e1e615b0c008e4ae708a7cf..aab059e630c6f72f6f5311dd2100b8c2e8dcc1ae 100644 --- a/sflphone-client-gnome/pixmaps/Makefile.am +++ b/sflphone-client-gnome/pixmaps/Makefile.am @@ -2,7 +2,7 @@ icondir = $(datadir)/pixmaps icon_DATA = sflphone.svg -buttons_DATA = accept.svg current.svg transfert.svg hang_up.svg hold.svg unhold.svg refuse.svg call.svg ring.svg dial.svg mic.svg mic_25.svg mic_50.svg mic_75.svg speaker.svg speaker_25.svg speaker_50.svg speaker_75.svg fail.svg incoming.svg outgoing.svg missed.svg mailbox.svg busy.svg icon_accept.svg icon_hold.svg icon_unhold.svg icon_hangup.svg icon_call.svg icon_dialpad.svg icon_volume.svg icon_dialpad_off.svg icon_volume_off.svg history2.svg sflphone.svg sflphone_small.svg stock_person.svg icon_rec.svg rec_call.svg addressbook.svg contact_default.svg face-monkey.svg users.svg home.svg wait-on.gif lock_certified.svg lock_confirmed.svg lock_error.svg lock_off.svg lock_unconfirmed.svg +buttons_DATA = accept.svg current.svg transfert.svg hang_up.svg hold.svg unhold.svg refuse.svg call.svg ring.svg dial.svg mic.svg mic_25.svg mic_50.svg mic_75.svg speaker.svg speaker_25.svg speaker_50.svg speaker_75.svg fail.svg incoming.svg outgoing.svg missed.svg mailbox.svg busy.svg icon_accept.svg icon_hold.svg icon_unhold.svg icon_hangup.svg icon_call.svg icon_dialpad.svg icon_volume.svg icon_dialpad_off.svg icon_volume_off.svg history2.svg sflphone.svg sflphone_small.svg stock_person.svg icon_rec.svg rec_call.svg addressbook.svg contact_default.svg face-monkey.svg users.svg usersActive.svg home.svg wait-on.gif lock_certified.svg lock_confirmed.svg lock_error.svg lock_off.svg lock_unconfirmed.svg buttonsdir = $(datadir)/sflphone EXTRA_DIST = $(buttons_DATA) $(icon_DATA) diff --git a/sflphone-client-gnome/pixmaps/usersActive.svg b/sflphone-client-gnome/pixmaps/usersActive.svg index 85b8e7977319198db0eda97e274e8f6a4dbb41eb..1a7d6fc90a389c329f6cee04ac1854290c517718 100644 --- a/sflphone-client-gnome/pixmaps/usersActive.svg +++ b/sflphone-client-gnome/pixmaps/usersActive.svg @@ -27,7 +27,7 @@ <stop id="stop4910" offset="0" - style="stop-color:#ff0000;stop-opacity:1;" /> + style="stop-color:#0000ff;stop-opacity:1;" /> <stop id="stop4912" offset="1" @@ -430,7 +430,7 @@ xlink:href="#linearGradient3824" id="linearGradient5073" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.33835,0,0,1.33835,19.045003,-13.796172)" + gradientTransform="matrix(1.33835,0,0,1.33835,-46.329997,-7.296172)" x1="30.935921" y1="29.553486" x2="30.935921" @@ -440,7 +440,7 @@ xlink:href="#linearGradient4356" id="linearGradient5075" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-1.308485,0.281154,0.281154,1.308485,91.615243,-19.308382)" + gradientTransform="matrix(-1.308485,0.281154,0.281154,1.308485,26.240243,-12.808382)" x1="22.686766" y1="36.390400" x2="21.408455" @@ -482,7 +482,7 @@ xlink:href="#linearGradient4908" id="radialGradient5083" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.046177,0,-2.580083e-8,1.017815,46.621787,0.6353743)" + gradientTransform="matrix(1.046177,0,-2.580083e-8,1.017815,-18.753213,7.1353743)" cx="24.753788" cy="26.814409" fx="24.753788" @@ -493,7 +493,7 @@ xlink:href="#linearGradient4356" id="linearGradient5085" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-0.999008,0.214863,0.214657,0.999968,97.340213,-6.148422)" + gradientTransform="matrix(-0.999008,0.214863,0.214657,0.999968,31.965213,0.351578)" x1="22.686766" y1="36.390400" x2="21.408455" @@ -503,7 +503,7 @@ xlink:href="#linearGradient4356" id="linearGradient5087" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.004822,0.185726,-0.185548,1.005788,46.523971,-4.993292)" + gradientTransform="matrix(1.004822,0.185726,-0.185548,1.005788,-18.851029,1.506708)" x1="20.661695" y1="35.817974" x2="22.626925" @@ -541,16 +541,16 @@ inkscape:zoom="8" inkscape:cx="31.452526" inkscape:cy="23.601838" - inkscape:current-layer="layer2" + inkscape:current-layer="g5058" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" fill="#9db029" stroke="#727e0a" - inkscape:window-width="1920" + inkscape:window-width="1910" inkscape:window-height="1003" inkscape:window-x="0" - inkscape:window-y="25" /> + inkscape:window-y="143" /> <metadata id="metadata4"> <rdf:RDF> @@ -604,18 +604,18 @@ style="display:inline"> <g id="g5058" - transform="translate(-42.497844,-5.9675144)"> + transform="translate(23.252156,-12.592514)"> <path id="path2498" - d="M 65.889651,31.754099 L 71.567789,31.754099 L 68.255543,28.67844 L 67.545775,29.624797 L 66.836007,28.91503 L 65.889651,31.754099 z" + d="M 0.514651,38.254099 L 6.192789,38.254099 L 2.880543,35.17844 L 2.170775,36.124797 L 1.461007,35.41503 L 0.514651,38.254099 z" style="opacity:0.78857141;fill:url(#linearGradient5073);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> <path style="opacity:0.17967446;fill:url(#linearGradient5075);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 72.407105,39.394412 C 74.05495,38.61686 74.821997,36.714605 74.821997,36.714605 C 73.538359,31.303678 69.500518,27.556514 69.500518,27.556514 C 69.500518,27.556514 72.799006,36.045137 72.407105,39.394412 z" + d="M 7.032105,45.894412 C 8.67995,45.11686 9.446997,43.214605 9.446997,43.214605 C 8.163359,37.803678 4.125518,34.056514 4.125518,34.056514 C 4.125518,34.056514 7.424006,42.545137 7.032105,45.894412 z" id="path2500" sodipodi:nodetypes="cccc" /> <g - transform="matrix(1.443435e-2,0,0,1.697277e-2,85.708613,36.961608)" + transform="matrix(1.443435e-2,0,0,1.697277e-2,20.333613,43.461608)" id="g2502" style="opacity:0.78857141;display:inline"> <rect @@ -639,13 +639,13 @@ <path sodipodi:nodetypes="cczcczc" id="path2510" - d="M 67.372347,40.403867 L 78.336289,40.403867 C 81.44274,40.403867 84.518259,39.305326 85.645582,36.174277 C 86.716113,33.200974 85.828316,27.53886 78.884486,22.956803 L 65.910486,22.956803 C 58.966657,27.186393 58.098898,32.970738 59.697587,36.350509 C 61.326264,39.793675 64.083164,40.403867 67.372347,40.403867 z" + d="M 1.997347,46.903867 L 12.961289,46.903867 C 16.06774,46.903867 19.143259,45.805326 20.270582,42.674277 C 21.341113,39.700974 20.453316,34.03886 13.509486,29.456803 L 0.535486,29.456803 C -6.408343,33.686393 -7.276102,39.470738 -5.677413,42.850509 C -4.048736,46.293675 -1.291836,46.903867 1.997347,46.903867 z" style="opacity:1;fill:url(#radialGradient5083);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:0.99999928px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> <path inkscape:r_cy="true" inkscape:r_cx="true" style="opacity:0.22963891;fill:url(#linearGradient5085);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 82.675104,38.713326 C 83.933208,38.119107 84.518836,36.66537 84.518836,36.66537 C 83.538799,32.53024 80.455969,29.66659 80.455969,29.66659 C 80.455969,29.66659 82.974314,36.153749 82.675104,38.713326 z" + d="M 17.300104,45.213326 C 18.558208,44.619107 19.143836,43.16537 19.143836,43.16537 C 18.163799,39.03024 15.080969,36.16659 15.080969,36.16659 C 15.080969,36.16659 17.599314,42.653749 17.300104,45.213326 z" id="path2512" sodipodi:nodetypes="cccc" /> <path @@ -653,15 +653,15 @@ inkscape:r_cx="true" sodipodi:nodetypes="cccc" id="path2514" - d="M 62.48471,39.423138 C 61.209893,38.865747 60.639327,37.522507 60.639327,37.522507 C 61.498956,33.360629 64.440382,30.315697 64.440382,30.315697 C 64.440382,30.315697 62.11135,36.87334 62.48471,39.423138 z" + d="M -2.89029,45.923138 C -4.165107,45.365747 -4.735673,44.022507 -4.735673,44.022507 C -3.876044,39.860629 -0.934618,36.815697 -0.934618,36.815697 C -0.934618,36.815697 -3.26365,43.37334 -2.89029,45.923138 z" style="opacity:0.43328097;fill:url(#linearGradient5087);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> <path style="opacity:0.50693874;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999863px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 67.320507,39.403853 L 78.250226,39.381596 C 80.999701,39.381596 83.721793,38.406717 84.719571,35.628131 C 85.667083,32.989533 84.620911,27.964804 78.475034,23.898549 L 66.471159,23.653733 C 60.32528,27.407199 59.135735,32.540401 60.573725,35.784525 C 62.011717,39.028649 64.110095,39.381596 67.320507,39.403853 z" + d="M 1.945507,45.903853 L 12.875226,45.881596 C 15.624701,45.881596 18.346793,44.906717 19.344571,42.128131 C 20.292083,39.489533 19.245911,34.464804 13.100034,30.398549 L 1.096159,30.153733 C -5.04972,33.907199 -6.239265,39.040401 -4.801275,42.284525 C -3.363283,45.528649 -1.264905,45.881596 1.945507,45.903853 z" id="path2516" sodipodi:nodetypes="cczcczc" /> <path - transform="matrix(1.021809,0,0,1.022791,40.595633,1.5419983)" + transform="matrix(1.021809,0,0,1.022791,-24.779367,8.0419983)" sodipodi:type="arc" style="opacity:0.78857141;fill:url(#radialGradient5089);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" id="path2518" @@ -671,17 +671,17 @@ sodipodi:ry="8.6620579" d="M 39.774755,19.008621 A 8.6620579,8.6620579 0 1 1 22.45064,19.008621 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" /> <path - transform="matrix(0.981291,0,0,0.981291,41.993573,-0.7491257)" + transform="matrix(0.981291,0,0,0.981291,-23.381427,5.7508743)" d="M 39.774755,19.008621 A 8.6620579,8.6620579 0 1 1 22.45064,19.008621 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" sodipodi:ry="8.6620579" sodipodi:rx="8.6620579" sodipodi:cy="19.008621" sodipodi:cx="31.112698" id="path2520" - style="opacity:1;fill:url(#radialGradient5091);fill-opacity:1;fill-rule:evenodd;stroke:#8a8586;stroke-width:1.0190649px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + style="opacity:1;fill:url(#radialGradient5091);fill-opacity:1;fill-rule:evenodd;stroke:#8a8586;stroke-width:1.01906574;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" sodipodi:type="arc" /> <path - transform="matrix(0.865845,0,0,0.865845,45.585403,1.4453403)" + transform="matrix(0.865845,0,0,0.865845,-19.789597,7.9453403)" sodipodi:type="arc" style="opacity:0.41456329;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.15494144px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" id="path2522" diff --git a/sflphone-client-gnome/src/Makefile.am b/sflphone-client-gnome/src/Makefile.am index 80a6165a815494b99a923f4f9129b784f4e573a3..0d69be795377135e87800d62fde39adeb4a159e2 100644 --- a/sflphone-client-gnome/src/Makefile.am +++ b/sflphone-client-gnome/src/Makefile.am @@ -18,6 +18,7 @@ sflphone_client_gnome_SOURCES = \ menus.c \ toolbar.c \ callable_obj.c \ + conference_obj.c \ actions.c \ accountlist.c \ sliders.c \ @@ -27,7 +28,8 @@ sflphone_client_gnome_SOURCES = \ noinst_HEADERS = actions.h sflnotify.h mainwindow.h dialpad.h codeclist.h \ reqaccount.h errors.h sflphone_const.h \ - menus.h accountlist.h sliders.h statusicon.h callable_obj.h toolbar.h + menus.h accountlist.h sliders.h statusicon.h callable_obj.h conference_obj.h toolbar.h + sflphone_client_gnome_LDADD = $(DEPS_LIBS) $(NOTIFY_LIBS) $(SFLPHONEGTK_LIBS) $(LIBSEXY_LIBS) $(LOG4C) diff --git a/sflphone-client-gnome/src/actions.c b/sflphone-client-gnome/src/actions.c index 25bb9b11a4b6a547adff7fb59d35a4e5cf793e41..ff0c693730ee40d0bad7c3854c9d725a37e9f203 100644 --- a/sflphone-client-gnome/src/actions.c +++ b/sflphone-client-gnome/src/actions.c @@ -124,7 +124,7 @@ sflphone_quit () sflphone_hold (callable_obj_t * c ) { c->_state = CALL_STATE_HOLD; - calltree_update_call(current_calls,c); + calltree_update_call(current_calls, c, NULL); update_menus(); } @@ -132,7 +132,7 @@ sflphone_hold (callable_obj_t * c ) sflphone_ringing(callable_obj_t * c ) { c->_state = CALL_STATE_RINGING; - calltree_update_call(current_calls,c); + calltree_update_call(current_calls, c, NULL); update_menus(); } @@ -140,7 +140,7 @@ sflphone_ringing(callable_obj_t * c ) sflphone_hung_up( callable_obj_t * c) { calllist_remove( current_calls, c->_callID); - calltree_remove_call(current_calls, c); + calltree_remove_call(current_calls, c, NULL); c->_state = CALL_STATE_DIALING; call_remove_all_errors(c); update_menus(); @@ -279,6 +279,7 @@ gboolean sflphone_init() account_list_init (); codec_list_init(); + conferencelist_init(); // Fetch the configured accounts sflphone_fill_account_list(FALSE); @@ -289,6 +290,9 @@ gboolean sflphone_init() // Fetch the audio codecs sflphone_fill_codec_list(); + // Fetch the conference list + sflphone_fill_conference_list(); + return TRUE; } } @@ -350,7 +354,17 @@ sflphone_hang_up() break; } } - calltree_update_call( history , selectedCall ); + calltree_update_call(history, selectedCall, NULL); +} + + +void +sflphone_conference_hang_up() +{ + conference_obj_t * selectedConf = calltab_get_selected_conf(); + + if(selectedConf) + dbus_hang_up_conference(selectedConf); } @@ -370,7 +384,7 @@ sflphone_pick_up() break; case CALL_STATE_INCOMING: selectedCall->_history_state = INCOMING; - calltree_update_call( history , selectedCall ); + calltree_update_call( history, selectedCall, NULL); dbus_accept (selectedCall); DEBUG("from sflphone_pick_up : "); stop_notification(); break; @@ -453,7 +467,7 @@ sflphone_off_hold () sflphone_fail( callable_obj_t * c ) { c->_state = CALL_STATE_FAILURE; - calltree_update_call(current_calls,c); + calltree_update_call(current_calls, c, NULL); update_menus(); } @@ -461,7 +475,7 @@ sflphone_fail( callable_obj_t * c ) sflphone_busy( callable_obj_t * c ) { c->_state = CALL_STATE_BUSY; - calltree_update_call(current_calls, c); + calltree_update_call(current_calls, c, NULL); update_menus(); } @@ -471,7 +485,7 @@ sflphone_current( callable_obj_t * c ) if( c->_state != CALL_STATE_HOLD ) set_timestamp (&c->_time_start); c->_state = CALL_STATE_CURRENT; - calltree_update_call(current_calls,c); + calltree_update_call(current_calls, c, NULL); update_menus(); } @@ -481,7 +495,7 @@ sflphone_record( callable_obj_t * c ) if( c->_state != CALL_STATE_HOLD ) set_timestamp (&c->_time_start); c->_state = CALL_STATE_RECORD; - calltree_update_call(current_calls,c); + calltree_update_call(current_calls, c, NULL); update_menus(); } @@ -493,7 +507,7 @@ sflphone_set_transfert() { c->_state = CALL_STATE_TRANSFERT; c->_trsft_to = g_strdup(""); - calltree_update_call(current_calls,c); + calltree_update_call(current_calls, c, NULL); update_menus(); } toolbar_update_buttons(); @@ -507,7 +521,7 @@ sflphone_unset_transfert() { c->_state = CALL_STATE_CURRENT; c->_trsft_to = g_strdup(""); - calltree_update_call(current_calls,c); + calltree_update_call(current_calls, c, NULL); update_menus(); } toolbar_update_buttons(); @@ -525,7 +539,7 @@ sflphone_incoming_call (callable_obj_t * c) c->_history_state = MISSED; calllist_add ( current_calls, c ); calllist_add( history, c ); - calltree_add_call( current_calls , c ); + calltree_add_call( current_calls, c, NULL); update_menus(); calltree_display (current_calls); } @@ -566,7 +580,7 @@ process_dialing(callable_obj_t * c, guint keyval, gchar * key) g_free(before); DEBUG("TO: backspace %s", c->_peer_number); } - calltree_update_call(current_calls,c); + calltree_update_call(current_calls, c, NULL); } else if(strlen(c->_peer_number) == 0) { @@ -601,7 +615,7 @@ process_dialing(callable_obj_t * c, guint keyval, gchar * key) //g_free(c->_peer_name); //c->_peer_name = g_strconcat("\"\" <", c->_peer_number, ">", NULL); } - calltree_update_call(current_calls,c); + calltree_update_call(current_calls, c, NULL); } break; } @@ -627,7 +641,7 @@ sflphone_new_call() create_new_call (CALL, CALL_STATE_DIALING, "", "", peer_name, peer_number, &c); calllist_add (current_calls,c); - calltree_add_call (current_calls,c); + calltree_add_call (current_calls, c, NULL); update_menus(); return c; @@ -671,7 +685,7 @@ sflphone_keypad( guint keyval, gchar * key) case 65307: /* ESCAPE */ dbus_hang_up(c); set_timestamp (&c->_time_stop); - calltree_update_call( history , c ); + calltree_update_call(history, c, NULL); break; default: // To play the dtmf when calling mail box for instance @@ -694,7 +708,7 @@ sflphone_keypad( guint keyval, gchar * key) case 65293: /* ENTER */ case 65421: /* ENTER numpad */ c->_history_state = INCOMING; - calltree_update_call( history , c ); + calltree_update_call(history, c, NULL); dbus_accept(c); DEBUG("from sflphone_keypad ( enter ) : "); stop_notification(); break; @@ -744,7 +758,7 @@ sflphone_keypad( guint keyval, gchar * key) case 65307: /* ESCAPE */ dbus_hang_up(c); //c->_stop = 0; - calltree_update_call( history , c ); + calltree_update_call(history, c, NULL); break; } break; @@ -913,26 +927,125 @@ sflphone_get_current_codec_name() return dbus_get_current_codec_name(selectedCall); } + void +sflphone_detach_participant(const gchar* callID) +{ + DEBUG("sflphone detach participant from conference"); + + + + if(callID == NULL) { + callable_obj_t * selectedCall = calltab_get_selected_call(current_calls); + DEBUG(" sflphone_detach_participant %s\n", selectedCall->_callID); + + calltree_remove_call(current_calls, selectedCall, NULL); + calltree_add_call(current_calls, selectedCall, NULL); + dbus_detach_participant(selectedCall->_callID); + } + else { + callable_obj_t * selectedCall = calllist_get(current_calls, callID); + DEBUG(" sflphone_detach_participant %s\n", callID); + + calltree_remove_call(current_calls, selectedCall, NULL); + calltree_add_call(current_calls, selectedCall, NULL); + dbus_detach_participant(callID); + } + +} + + void +sflphone_join_participant(const gchar* sel_callID, const gchar* drag_callID) +{ + DEBUG("sflphone join participants %s and %s", sel_callID, drag_callID); + + + dbus_join_participant(sel_callID, drag_callID); +} + + + void +sflphone_add_participant(const gchar* callID, const gchar* confID) +{ + DEBUG("sflphone add participant %s to conference %s", callID, confID); + + dbus_add_participant(callID, confID); +} + + void +sflphone_add_conference() +{ + DEBUG("sflphone add a conference to tree view"); + // dbus_join_participant(selected_call, dragged_call); +} + + void +sflphone_join_conference(const gchar* sel_confID, const gchar* drag_confID) +{ + DEBUG("sflphone join two conference"); + dbus_join_conference(sel_confID, drag_confID); +} + +void +sflphone_add_main_participant(const conference_obj_t * c) +{ + DEBUG("sflphone add main participant"); + dbus_add_main_participant(c->_confID); +} + +void +sflphone_conference_on_hold(const conference_obj_t * c) +{ + DEBUG("sflphone_conference_on_hold"); + dbus_hold_conference(c); +} + +void +sflphone_conference_off_hold(const conference_obj_t * c) +{ + DEBUG("sflphone_conference_off_hold"); + dbus_unhold_conference(c); +} + + void sflphone_rec_call() { callable_obj_t * selectedCall = calltab_get_selected_call(current_calls); - dbus_set_record(selectedCall); + conference_obj_t * selectedConf = calltab_get_selected_conf(current_calls); - - switch(selectedCall->_state) + if(selectedCall) { - case CALL_STATE_CURRENT: - selectedCall->_state = CALL_STATE_RECORD; - break; - case CALL_STATE_RECORD: - selectedCall->_state = CALL_STATE_CURRENT; - break; - default: - WARN("Should not happen in sflphone_off_hold ()!"); - break; + dbus_set_record(selectedCall->_callID); + switch(selectedCall->_state) + { + case CALL_STATE_CURRENT: + selectedCall->_state = CALL_STATE_RECORD; + break; + case CALL_STATE_RECORD: + selectedCall->_state = CALL_STATE_CURRENT; + break; + default: + WARN("Should not happen in sflphone_off_hold ()!"); + break; + } } - calltree_update_call(current_calls,selectedCall); + else if(selectedConf) + { + dbus_set_record(selectedConf->_confID); + switch(selectedConf->_state) + { + case CONFERENCE_STATE_ACTIVE_ATACHED: + selectedCall->_state = CONFERENCE_STATE_RECORD; + break; + case CONFERENCE_STATE_RECORD: + selectedCall->_state = CONFERENCE_STATE_ACTIVE_ATACHED; + break; + default: + WARN("Should not happen in sflphone_off_hold ()!"); + break; + } + } + calltree_update_call(current_calls, selectedCall, NULL); update_menus(); // gchar* codname = sflphone_get_current_codec_name(); @@ -1019,11 +1132,38 @@ void sflphone_fill_call_list (void) DEBUG ("Add call retrieved from server side: %s\n", c->_callID); calllist_add (current_calls, c); // Update the GUI - calltree_add_call (current_calls, c); + calltree_add_call (current_calls, c, NULL); } } } + +void sflphone_fill_conference_list(void) +{ + gchar** conferences = (gchar**)dbus_get_conference_list(); + gchar** pl; + GHashTable *conference_details; + gchar* conf_id; + conference_obj_t* c; + + DEBUG("sflphone_fill_conference_list"); + + if(conferences) + { + for (pl = conferences; *conferences; conferences++) + { + c = g_new0(conference_obj_t, 1); + conf_id = (gchar*)(*conferences); + + conference_details = dbus_get_conference_details(conf_id); + create_new_call_from_details (conf_id, conference_details, &c); + c->_confID = g_strdup(conf_id); + + conferencelist_add(c); + } + } +} + void sflphone_fill_history (void) { GHashTable *entries; @@ -1086,7 +1226,7 @@ sflphone_srtp_on( callable_obj_t * c) { c->_srtp_state = SRTP_STATE_SAS_UNCONFIRMED; - calltree_update_call(current_calls, c); + calltree_update_call(current_calls, c, NULL); update_menus(); } @@ -1094,7 +1234,7 @@ sflphone_srtp_on( callable_obj_t * c) sflphone_srtp_off( callable_obj_t * c ) { c->_srtp_state = SRTP_STATE_UNLOCKED; - calltree_update_call(current_calls, c); + calltree_update_call(current_calls, c, NULL); update_menus(); } @@ -1110,7 +1250,7 @@ sflphone_srtp_show_sas( callable_obj_t * c, const gchar* sas, const gboolean ver } else { c->_srtp_state = SRTP_STATE_SAS_UNCONFIRMED; } - calltree_update_call(current_calls, c); + calltree_update_call(current_calls, c, NULL); update_menus(); } @@ -1158,6 +1298,6 @@ sflphone_call_state_changed( callable_obj_t * c, const gchar * description, cons c->_state_code = code; } - calltree_update_call(current_calls, c); + calltree_update_call(current_calls, c, NULL); update_menus(); } diff --git a/sflphone-client-gnome/src/actions.h b/sflphone-client-gnome/src/actions.h index f201c248ef9814d78f6819e3af6a3be539ecaaa3..083ba441482b63e76bd8f09a1a6b8f403eaef6c1 100644 --- a/sflphone-client-gnome/src/actions.h +++ b/sflphone-client-gnome/src/actions.h @@ -28,6 +28,7 @@ #include <codeclist.h> #include <sflphone_const.h> #include <errors.h> +#include <conference_obj.h> /** @file actions.h * @brief General functions that change the state of the application. @@ -178,6 +179,8 @@ void sflphone_set_current_account(); */ void sflphone_fill_codec_list(); +void sflphone_add_participant(); + void sflphone_record (callable_obj_t *c); void sflphone_rec_call (void); @@ -192,6 +195,14 @@ void sflphone_fill_history (void); void sflphone_save_history (void); +void sflphone_join_participant(const gchar* sel_callID, const gchar* drag_callID); + +void sflphone_add_participant(const gchar* callID, const gchar* confID); + +void sflphone_detach_participant(const gchar* callID); + +void sflphone_join_conference(const gchar* sel_confID, const gchar* drag_confID); + /** Nofity that the communication is * now secured. * @param c* The current call @@ -243,4 +254,5 @@ void sflphone_request_go_clear(void); void sflphone_call_state_changed(callable_obj_t * c, const gchar * description, const guint code); + #endif diff --git a/sflphone-client-gnome/src/conference_obj.c b/sflphone-client-gnome/src/conference_obj.c new file mode 100644 index 0000000000000000000000000000000000000000..52e31bff503118de5b38fde2f2fcefc375a72328 --- /dev/null +++ b/sflphone-client-gnome/src/conference_obj.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <callable_obj.h> +#include <sflphone_const.h> +#include <time.h> + +gint is_confID_confstruct ( gconstpointer a, gconstpointer b) +{ + conference_obj_t * c = (conference_obj_t*)a; + if(g_strcasecmp(c->_confID, (const gchar*) b) == 0) + { + return 0; + } + else + { + return 1; + } +} + +void create_new_conference (conference_state_t state, const gchar* confID, conference_obj_t ** new_conf) +{ + + conference_obj_t *obj; + gchar *conf_id; + + // Allocate memory + obj = g_new0 (conference_obj_t, 1); + + // Set state field + obj->_state = state; + + // Set the ID field + conf_id = confID; + obj->_confID = g_strdup (conf_id); + *new_conf = obj; + +} + +void create_new_conference_from_details (const gchar *conf_id, GHashTable *details, conference_obj_t *conf) +{ + /* + gchar *peer_name, *peer_number, *accountID, *state_str; + callable_obj_t *new_call; + call_state_t state; + + accountID = g_hash_table_lookup (details, "ACCOUNTID"); + peer_number = g_hash_table_lookup (details, "PEER_NUMBER"); + peer_name = g_strdup (""); + state_str = g_hash_table_lookup (details, "CALL_STATE"); + + + if (g_strcasecmp (state_str, "CURRENT") == 0) + state = CALL_STATE_CURRENT; + + else if (g_strcasecmp (state_str, "RINGING") == 0) + state = CALL_STATE_RINGING; + + else if (g_strcasecmp (state_str, "INCOMING") == 0) + state = CALL_STATE_INCOMING; + + else if (g_strcasecmp (state_str, "HOLD") == 0) + state = CALL_STATE_HOLD; + + else if (g_strcasecmp (state_str, "BUSY") == 0) + state = CALL_STATE_BUSY; + + else + state = CALL_STATE_FAILURE; + + create_new_call (CALL, state, (gchar*)call_id, accountID, peer_name, peer_number, &new_call); + *call = new_call; + */ +} + +void free_conference_obj_t (conference_obj_t *c) +{ + g_free (c->_confID); + g_free (c); +} diff --git a/sflphone-client-gnome/src/conference_obj.h b/sflphone-client-gnome/src/conference_obj.h new file mode 100644 index 0000000000000000000000000000000000000000..7f0dac5cb10d5ed9b755b0b869f366c7d795c503 --- /dev/null +++ b/sflphone-client-gnome/src/conference_obj.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __CONFERENCE_OBJ_H__ +#define __CONFERENCE_OBJ_H__ + +#include <gtk/gtk.h> +#include <glib/gprintf.h> +#include <stdlib.h> +#include <time.h> + + + +/** @enum conference_state_t + * This enum have all the states a conference can take. + */ +typedef enum +{ + CONFERENCE_STATE_ACTIVE_ATACHED = 0, + CONFERENCE_STATE_ACTIVE_DETACHED, + CONFERENCE_STATE_RECORD, + CONFERENCE_STATE_HOLD +} conference_state_t; + + +/** @struct conference_obj_t + * @brief Conference information. + * This struct holds information about a conference. + */ +typedef struct { + + conference_state_t _state; // The state of the call + gchar* _confID; // The call ID + gboolean _conference_secured; // the security state of the conference + gboolean _conf_srtp_enabled; // security required for this conference + +} conference_obj_t; + +void create_new_conference (conference_state_t, const gchar*, conference_obj_t **); + +void create_new_conference_from_details (const gchar *, GHashTable *, conference_obj_t *); + +void free_conference_obj_t (conference_obj_t *c); + +/* + * GCompareFunc to compare a confID (gchar* and a callable_obj_t) + */ +gint is_confID_confstruct ( gconstpointer, gconstpointer); + +#endif diff --git a/sflphone-client-gnome/src/contacts/Makefile.am b/sflphone-client-gnome/src/contacts/Makefile.am index 8afd0f4dc01a53dfd633191c6663ade77b3fcd8e..288196626b1825dc76be5d094d32f81ed8d7bfbe 100644 --- a/sflphone-client-gnome/src/contacts/Makefile.am +++ b/sflphone-client-gnome/src/contacts/Makefile.am @@ -10,7 +10,8 @@ libcontacts_la_SOURCES = \ calltab.c \ calltree.c \ history.c \ - addressbook.c + addressbook.c \ + conferencelist.c libcontacts_la_LDFLAGS = @DEPS_LDFLAGS@ diff --git a/sflphone-client-gnome/src/contacts/calllist.c b/sflphone-client-gnome/src/contacts/calllist.c index 7bcf5f75d9dac8e836a96813e43fe2334f56ab1c..5fba11456bd82991a90034b38f31eb6ba51a1b7b 100644 --- a/sflphone-client-gnome/src/contacts/calllist.c +++ b/sflphone-client-gnome/src/contacts/calllist.c @@ -54,7 +54,7 @@ void calllist_add_contact (gchar *contact_name, gchar *contact_phone, contact_ty } calllist_add (contacts, new_call); - calltree_add_call(contacts, new_call); + calltree_add_call(contacts, new_call, NULL); } } @@ -83,7 +83,7 @@ void calllist_add_history_entry (callable_obj_t *obj) if ( g_strcasecmp (dbus_get_history_enabled (), "true") == 0) { g_queue_push_tail (history->callQueue, (gpointer *) obj); - calltree_add_call (history, obj); + calltree_add_call (history, obj, NULL); } } @@ -111,7 +111,7 @@ calllist_clean_history( void ) callable_obj_t* c = calllist_get_nth( history , i ); // Delete the call from the call tree DEBUG("Delete calls"); - calltree_remove_call(history , c); + calltree_remove_call(history, c, NULL); } calllist_reset( history ); } @@ -121,7 +121,7 @@ void calllist_remove_from_history( callable_obj_t* c ) { calllist_remove( history, c->_callID ); - calltree_remove_call( history, c ); + calltree_remove_call(history, c, NULL); DEBUG("Size of history = %i" , calllist_get_size( history )); } diff --git a/sflphone-client-gnome/src/contacts/calllist.h b/sflphone-client-gnome/src/contacts/calllist.h index 3caccad439c4689374c411b296125ac8cff5bf18..befb97048e8a867298551eb1afb69a2a584678b7 100644 --- a/sflphone-client-gnome/src/contacts/calllist.h +++ b/sflphone-client-gnome/src/contacts/calllist.h @@ -21,6 +21,7 @@ #define __CALLLIST_H__ #include <callable_obj.h> +#include <conference_obj.h> #include <gtk/gtk.h> /** @file calllist.h @@ -28,15 +29,17 @@ */ typedef struct { - GtkListStore* store; + GtkTreeStore* store; GtkWidget* view; GtkWidget* tree; - GtkWidget* searchbar; + GtkWidget* searchbar; - // Calllist vars + // Calllist vars GQueue* callQueue; + gint selectedType; callable_obj_t* selectedCall; - gchar *_name; + conference_obj_t* selectedConf; + gchar *_name; } calltab_t; void diff --git a/sflphone-client-gnome/src/contacts/calltab.c b/sflphone-client-gnome/src/contacts/calltab.c index 00cfc85343213d062e0b11d96d35dc2737300745..f832d6c561f5c65baa091b0e13b80c1c48d2cfe6 100644 --- a/sflphone-client-gnome/src/contacts/calltab.c +++ b/sflphone-client-gnome/src/contacts/calltab.c @@ -32,10 +32,11 @@ calltab_t* calltab_init (gboolean searchbar_type, gchar *name) ret->store = NULL; ret->view = NULL; ret->tree = NULL; - ret->searchbar = NULL; + ret->searchbar = NULL; ret->callQueue = NULL; ret->selectedCall = NULL; - ret->_name = g_strdup (name); + ret->selectedConf = NULL; + ret->_name = g_strdup (name); calltree_create (ret, searchbar_type); calllist_init(ret); @@ -47,16 +48,36 @@ calltab_t* calltab_init (gboolean searchbar_type, gchar *name) void calltab_select_call (calltab_t* tab, callable_obj_t * c ) { - tab->selectedCall = c; + tab->selectedType = A_CALL; + tab->selectedCall = c; } +void +calltab_select_conf (conference_obj_t * c ) +{ + current_calls->selectedType = A_CONFERENCE; + current_calls->selectedConf = c; +} + +gint +calltab_get_selected_type(calltab_t* tab) +{ + return tab->selectedType; +} + callable_obj_t * calltab_get_selected_call (calltab_t* tab) { return tab->selectedCall; } +conference_obj_t* +calltab_get_selected_conf () +{ + return current_calls->selectedConf; +} + void calltab_create_searchbar (calltab_t* tab) { diff --git a/sflphone-client-gnome/src/contacts/calltab.h b/sflphone-client-gnome/src/contacts/calltab.h index 25c3ddb70f99effcd6f507e3a169821e9ca25eb5..bf3b11b8407efda3ab1e7a74c4ff9b3050279860 100644 --- a/sflphone-client-gnome/src/contacts/calltab.h +++ b/sflphone-client-gnome/src/contacts/calltab.h @@ -21,6 +21,7 @@ #define __CALLTAB_H__ #include <calllist.h> +#include <conferencelist.h> #include <gtk/gtk.h> calltab_t* active_calltree; @@ -30,17 +31,28 @@ calltab_t* contacts; calltab_t* calltab_init (gboolean searchbar_type, gchar *name); + + /** Mark a call as selected. There can be only one selected call. This call * is the currently highlighted one in the list. * @param c The call */ void calltab_select_call (calltab_t*, callable_obj_t *); +void +calltab_select_conf (conference_obj_t *); + +gint +calltab_get_selected_type(calltab_t* tab); + /** Return the selected call. * @return The number of the caller */ callable_obj_t * calltab_get_selected_call (calltab_t*); +conference_obj_t * +calltab_get_selected_conf (); + void calltab_create_searchbar (calltab_t *); diff --git a/sflphone-client-gnome/src/contacts/calltree.c b/sflphone-client-gnome/src/contacts/calltree.c index 96cebea0d8477da5bb08d7b126e33e9db7d4cb2f..40e772bbd67c1823fdc43edc16bfb7c1b5d9b101 100644 --- a/sflphone-client-gnome/src/contacts/calltree.c +++ b/sflphone-client-gnome/src/contacts/calltree.c @@ -2,6 +2,7 @@ * Copyright (C) 2007 Savoir-Faire Linux inc. * Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com> * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +23,7 @@ #include <stdlib.h> #include <glib/gprintf.h> #include <calllist.h> +#include <conferencelist.h> #include <toolbar.h> #include <mainwindow.h> #include <history.h> @@ -31,6 +33,30 @@ GtkCellRenderer *rend; GtkTreeViewColumn *col; GtkTreeSelection *sel; +gint dragged_type; +gint selected_type; + +gchar *dragged_call_id; +gchar *selected_call_id; + +gchar *dragged_path; +gchar *selected_path; + +gint dragged_path_depth; +gint selected_path_depth; + +callable_obj_t *dragged_call; +callable_obj_t *selected_call; + +conference_obj_t *dragged_conf; +conference_obj_t *selected_conf; + + +static void drag_begin_cb(GtkWidget *widget, GdkDragContext *dc, gpointer data); +static void drag_end_cb(GtkWidget * mblist, GdkDragContext * context, gpointer data); +void drag_data_received_cb(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t, gpointer data); + + enum { COLUMN_ACCOUNT_STATE = 0, COLUMN_ACCOUNT_DESC, @@ -38,10 +64,11 @@ enum { COLUMN_ACCOUNT_PTR, }; + /** * Show popup menu */ - static gboolean +static gboolean popup_menu (GtkWidget *widget, gpointer user_data UNUSED) { @@ -50,87 +77,170 @@ popup_menu (GtkWidget *widget, } /* Call back when the user click on a call in the list */ - static void +static void call_selected_cb(GtkTreeSelection *sel, void* data UNUSED ) { - GtkTreeIter iter; + + DEBUG("Selection Callback"); + + GtkTreeIter iter; GValue val; GtkTreeModel *model = (GtkTreeModel*)active_calltree->store; + GtkTreePath* path; + gchar* string_path; + + if (! gtk_tree_selection_get_selected (sel, &model, &iter)) return; - val.g_type = 0; - gtk_tree_model_get_value (model, &iter, COLUMN_ACCOUNT_PTR, &val); - calltab_select_call(active_calltree, (callable_obj_t*) g_value_get_pointer(&val)); - g_value_unset(&val); + // store info for dragndrop + path = gtk_tree_model_get_path(model, &iter); + string_path = gtk_tree_path_to_string(path); + selected_path_depth = gtk_tree_path_get_depth(path); + + if(gtk_tree_model_iter_has_child(GTK_TREE_MODEL(model), &iter)) + { + DEBUG("SELECTED A CONFERENCE"); + selected_type = A_CONFERENCE; + + val.g_type = 0; + gtk_tree_model_get_value (model, &iter, COLUMN_ACCOUNT_PTR, &val); + + calltab_select_conf((conference_obj_t*) g_value_get_pointer(&val)); + selected_conf = (conference_obj_t*)g_value_get_pointer(&val); + + if(selected_conf) + { + + selected_call_id = selected_conf->_confID; + selected_path = string_path; + + } + + } + else + { + DEBUG("SELECTED A CALL"); + selected_type = A_CALL; + // gtk_tree_model_iter_parent(GTK_TREE_MODEL(model), parent_conference, &iter); + + val.g_type = 0; + gtk_tree_model_get_value (model, &iter, COLUMN_ACCOUNT_PTR, &val); + + calltab_select_call(active_calltree, (callable_obj_t*) g_value_get_pointer(&val)); + + selected_call = (callable_obj_t*)g_value_get_pointer(&val); + + selected_call_id = selected_call->_callID; + selected_path = string_path; + } + + DEBUG("selected_cb\n"); + DEBUG(" selected_path %s, selected_call_id %s, selected_path_depth %i\n", selected_path, selected_call_id, selected_path_depth); + + // conferencelist_reset (); + // sflphone_fill_conference_list(); + + g_value_unset(&val); toolbar_update_buttons(); - // set_focus_on_mainwindow(); } /* A row is activated when it is double clicked */ -void row_activated(GtkTreeView *tree_view UNUSED, +void +row_activated(GtkTreeView *tree_view UNUSED, GtkTreePath *path UNUSED, GtkTreeViewColumn *column UNUSED, void * data UNUSED) { - callable_obj_t* selectedCall; + callable_obj_t* selectedCall = NULL; callable_obj_t* new_call; + conference_obj_t* selectedConf = NULL; gchar *account_id; DEBUG("double click action"); - selectedCall = calltab_get_selected_call( active_calltree ); - - if (selectedCall) + if( active_calltree == current_calls ) { - // Get the right event from the right calltree - if( active_calltree == current_calls ) - { - switch(selectedCall->_state) - { - case CALL_STATE_INCOMING: - dbus_accept(selectedCall); - stop_notification(); - break; - case CALL_STATE_HOLD: - dbus_unhold(selectedCall); - break; - case CALL_STATE_RINGING: - case CALL_STATE_CURRENT: - case CALL_STATE_BUSY: - case CALL_STATE_FAILURE: - break; - case CALL_STATE_DIALING: - sflphone_place_call (selectedCall); - break; - default: - WARN("Row activated - Should not happen!"); - break; - } - } - - // If history or contact: double click action places a new call - else - { - account_id = g_strdup (selectedCall->_accountID); - - // Create a new call - create_new_call (CALL, CALL_STATE_DIALING, "", account_id, selectedCall->_peer_name, selectedCall->_peer_number, &new_call); - - calllist_add(current_calls, new_call); - calltree_add_call(current_calls, new_call); - sflphone_place_call(new_call); - calltree_display(current_calls); - } + + if(calltab_get_selected_type(current_calls) == A_CALL) + { + selectedCall = calltab_get_selected_call(current_calls); + + if (selectedCall) + { + // Get the right event from the right calltree + if( active_calltree == current_calls ) + { + switch(selectedCall->_state) + { + case CALL_STATE_INCOMING: + dbus_accept(selectedCall); + stop_notification(); + break; + case CALL_STATE_HOLD: + dbus_unhold(selectedCall); + break; + case CALL_STATE_RINGING: + case CALL_STATE_CURRENT: + case CALL_STATE_BUSY: + case CALL_STATE_FAILURE: + break; + case CALL_STATE_DIALING: + sflphone_place_call (selectedCall); + break; + default: + WARN("Row activated - Should not happen!"); + break; + } + } + + // If history or contact: double click action places a new call + else + { + account_id = g_strdup (selectedCall->_accountID); + + // Create a new call + create_new_call (CALL, CALL_STATE_DIALING, "", account_id, selectedCall->_peer_name, selectedCall->_peer_number, &new_call); + + calllist_add(current_calls, new_call); + calltree_add_call(current_calls, new_call, NULL); + sflphone_place_call(new_call); + calltree_display(current_calls); + } + } + } + else + { + selectedConf = calltab_get_selected_conf(current_calls); + + if(selectedConf) + { + switch(selectedConf->_state) + { + case CONFERENCE_STATE_ACTIVE_ATACHED: + sflphone_add_main_participant(selectedConf); + break; + case CONFERENCE_STATE_ACTIVE_DETACHED: + sflphone_add_main_participant(selectedConf); + break; + case CONFERENCE_STATE_HOLD: + sflphone_conference_off_hold(selectedConf); + break; + } + } + } } + + } /* Catch cursor-activated signal. That is, when the entry is single clicked */ -void row_single_click(GtkTreeView *tree_view UNUSED, void * data UNUSED) +void +row_single_click(GtkTreeView *tree_view UNUSED, void * data UNUSED) { DEBUG("single click action"); callable_obj_t * selectedCall=NULL; @@ -167,12 +277,12 @@ void row_single_click(GtkTreeView *tree_view UNUSED, void * data UNUSED) selectedCall->_zrtp_confirmed = TRUE; } dbus_confirm_sas(selectedCall); - calltree_update_call(current_calls, selectedCall); + calltree_update_call(current_calls, selectedCall, NULL); break; case SRTP_STATE_SAS_CONFIRMED: selectedCall->_srtp_state = SRTP_STATE_SAS_UNCONFIRMED; dbus_reset_sas(selectedCall); - calltree_update_call(current_calls, selectedCall); + calltree_update_call(current_calls, selectedCall, NULL); break; default: DEBUG("Single click but no action"); @@ -182,7 +292,7 @@ void row_single_click(GtkTreeView *tree_view UNUSED, void * data UNUSED) } } - static gboolean +static gboolean button_pressed(GtkWidget* widget, GdkEventButton *event, gpointer user_data UNUSED) { if (event->button == 3 && event->type == GDK_BUTTON_PRESS) @@ -208,10 +318,10 @@ button_pressed(GtkWidget* widget, GdkEventButton *event, gpointer user_data UNUS /** * Reset call tree */ - void +void calltree_reset (calltab_t* tab) { - gtk_list_store_clear (tab->store); + gtk_tree_store_clear (tab->store); } void @@ -228,7 +338,7 @@ focus_on_calltree_in(){ focus_is_on_calltree = TRUE; } - void +void calltree_create (calltab_t* tab, gboolean searchbar_type) { @@ -243,7 +353,8 @@ calltree_create (calltab_t* tab, gboolean searchbar_type) gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); - tab->store = gtk_list_store_new (4, + + tab->store = gtk_tree_store_new (4, GDK_TYPE_PIXBUF,// Icon G_TYPE_STRING, // Description GDK_TYPE_PIXBUF, // Security Icon @@ -280,6 +391,23 @@ calltree_create (calltab_t* tab, gboolean searchbar_type) g_signal_connect_after (G_OBJECT (tab->view), "focus-out-event", G_CALLBACK (focus_on_calltree_out), NULL); + + if(tab != history || tab!=contacts) { + + DEBUG("SET TREE VIEW REORDABLE"); + // Make calltree reordable for drag n drop + gtk_tree_view_set_reorderable(GTK_TREE_VIEW(tab->view), TRUE); + + // source widget drag n drop signals + g_signal_connect (G_OBJECT (tab->view), "drag_begin", G_CALLBACK (drag_begin_cb), NULL); + g_signal_connect (G_OBJECT (tab->view), "drag_end", G_CALLBACK (drag_end_cb), NULL); + + // destination widget drag n drop signals + g_signal_connect (G_OBJECT (tab->view), "drag_data_received", G_CALLBACK (drag_data_received_cb), NULL); + + } + + gtk_widget_grab_focus(GTK_WIDGET(tab->view)); rend = gtk_cell_renderer_pixbuf_new(); @@ -328,20 +456,29 @@ calltree_create (calltab_t* tab, gboolean searchbar_type) gtk_widget_show(tab->tree); } - void -calltree_remove_call (calltab_t* tab, callable_obj_t * c) + +void +calltree_remove_call (calltab_t* tab, callable_obj_t * c, GtkTreeIter *parent) { + + DEBUG("calltree_remove_call %s", c->_callID); + GtkTreeIter iter; GValue val; callable_obj_t * iterCall; - GtkListStore* store = tab->store; + GtkTreeStore* store = tab->store; - int nbChild = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL); + int nbChild = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), parent); int i; for( i = 0; i < nbChild; i++) { - if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, i)) + if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, parent, i)) { + if(gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter)) + { + calltree_remove_call (tab, c, &iter); + } + val.g_type = 0; gtk_tree_model_get_value (GTK_TREE_MODEL(store), &iter, COLUMN_ACCOUNT_PTR, &val); @@ -350,7 +487,7 @@ calltree_remove_call (calltab_t* tab, callable_obj_t * c) if(iterCall == c) { - gtk_list_store_remove(store, &iter); + gtk_tree_store_remove(store, &iter); } } } @@ -360,22 +497,24 @@ calltree_remove_call (calltab_t* tab, callable_obj_t * c) toolbar_update_buttons(); } - void -calltree_update_call (calltab_t* tab, callable_obj_t * c) +void +calltree_update_call (calltab_t* tab, callable_obj_t * c, GtkTreeIter *parent) { GdkPixbuf *pixbuf=NULL; GdkPixbuf *pixbuf_security=NULL; GtkTreeIter iter; GValue val; callable_obj_t * iterCall; - GtkListStore* store = tab->store; + GtkTreeStore* store = tab->store; + gchar* srtp_enabled = ""; gboolean display_sas = TRUE; account_t* account_details=NULL; + - int nbChild = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL); + int nbChild = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), parent); int i; - + if(c != NULL) { account_details = account_list_get_by_id(c->_accountID); if(account_details != NULL) { @@ -391,190 +530,157 @@ calltree_update_call (calltab_t* tab, callable_obj_t * c) } } } - + for( i = 0; i < nbChild; i++) { - if(!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, i)) { - continue; - } - - val.g_type = 0; - gtk_tree_model_get_value (GTK_TREE_MODEL(store), &iter, COLUMN_ACCOUNT_PTR, &val); - iterCall = (callable_obj_t*) g_value_get_pointer(&val); - g_value_unset(&val); + if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, parent, i)) + { - if(iterCall != c) { - continue; - } + if(gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter)) + { + calltree_update_call (tab, c, &iter); + } + + val.g_type = 0; + gtk_tree_model_get_value (GTK_TREE_MODEL(store), &iter, COLUMN_ACCOUNT_PTR, &val); + + + iterCall = (callable_obj_t*) g_value_get_pointer(&val); + g_value_unset(&val); + + if(iterCall != c) { + continue; + } - /* Update text */ - gchar * description; - gchar * date=""; - gchar * duration=""; + /* Update text */ + gchar * description; + gchar * date=""; + gchar * duration=""; - if(c->_state == CALL_STATE_TRANSFERT) - { - description = g_markup_printf_escaped("<b>%s</b> <i>%s</i>\n<i>Transfert to:%s</i> ", - c->_peer_number, - c->_peer_name, - c->_trsft_to - ); - } - else - { - // c->_zrtp_confirmed == FALSE : Hack explained in callable_obj.h - if((c->_sas != NULL) && (display_sas == TRUE) && (c->_srtp_state == SRTP_STATE_SAS_UNCONFIRMED) && (c->_zrtp_confirmed == FALSE)) { - description = g_markup_printf_escaped("<b>%s</b> <i>%s</i>\n<i>Confirm SAS <b>%s</b> ?</i> ", - c->_peer_number, - c->_peer_name, - c->_sas - ); - } else { - DEBUG("Updating state code %d %s", c->_state_code, c->_state_code_description); - if (c->_state_code) { - description = g_markup_printf_escaped("<b>%s</b> <i>%s</i>\n<i>%s (%d)</i>", - c->_peer_number, - c->_peer_name, - c->_state_code_description, - c->_state_code); - } else { - description = g_markup_printf_escaped("<b>%s</b> <i>%s</i>", - c->_peer_number, - c->_peer_name ); + if(c->_state == CALL_STATE_TRANSFERT) + { + description = g_markup_printf_escaped("<b>%s</b> <i>%s</i>\n<i>Transfert to:%s</i> ", + c->_peer_number, + c->_peer_name, + c->_trsft_to); + } + else + { + // c->_zrtp_confirmed == FALSE : Hack explained in callable_obj.h + if((c->_sas != NULL) && (display_sas == TRUE) && (c->_srtp_state == SRTP_STATE_SAS_UNCONFIRMED) && (c->_zrtp_confirmed == FALSE)) { + description = g_markup_printf_escaped("<b>%s</b> <i>%s</i>\n<i>Confirm SAS <b>%s</b> ?</i> ", + c->_peer_number, + c->_peer_name, + c->_sas); + } else { + DEBUG("Updating state code %d %s", c->_state_code, c->_state_code_description); + if (c->_state_code) { + description = g_markup_printf_escaped("<b>%s</b> <i>%s</i>\n<i>%s (%d)</i>", + c->_peer_number, + c->_peer_name, + c->_state_code_description, + c->_state_code); + } else { + description = g_markup_printf_escaped("<b>%s</b> <i>%s</i>", + c->_peer_number, + c->_peer_name ); + } + } + } + + /* Update icons */ + if( tab == current_calls ) + { + DEBUG("Receiving in state %d", c->_state); + switch(c->_state) + { + case CALL_STATE_HOLD: + pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/hold.svg", NULL); + break; + case CALL_STATE_INCOMING: + case CALL_STATE_RINGING: + pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/ring.svg", NULL); + break; + case CALL_STATE_CURRENT: + pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/current.svg", NULL); + break; + case CALL_STATE_DIALING: + pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/dial.svg", NULL); + break; + case CALL_STATE_FAILURE: + pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/fail.svg", NULL); + break; + case CALL_STATE_BUSY: + pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/busy.svg", NULL); + break; + case CALL_STATE_TRANSFERT: + pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/transfert.svg", NULL); + break; + case CALL_STATE_RECORD: + pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/icon_rec.svg", NULL); + break; + default: + WARN("Update calltree - Should not happen!"); + } + + switch(c->_srtp_state) + { + case SRTP_STATE_SAS_UNCONFIRMED: + DEBUG("Secure is ON"); + pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_unconfirmed.svg", NULL); + if(c->_sas != NULL) { DEBUG("SAS is ready with value %s", c->_sas); } + break; + case SRTP_STATE_SAS_CONFIRMED: + DEBUG("SAS is confirmed"); + pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_confirmed.svg", NULL); + break; + case SRTP_STATE_SAS_SIGNED: + DEBUG("Secure is ON with SAS signed and verified"); + pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_certified.svg", NULL); + break; + case SRTP_STATE_UNLOCKED: + DEBUG("Secure is off calltree %d", c->_state); + if(g_strcasecmp(srtp_enabled,"true") == 0) { + pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_off.svg", NULL); + } + break; + default: + WARN("Update calltree srtp state #%d- Should not happen!", c->_srtp_state); + if(g_strcasecmp(srtp_enabled,"true") == 0) { + pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_off.svg", NULL); + } + } - } - } + gtk_tree_store_set(store, &iter, + 0, pixbuf, // Icon + 1, description, // Description + 2, pixbuf_security, + 3, c, + -1); - /* Update icons */ - if( tab == current_calls ) - { - DEBUG("Receiving in state %d", c->_state); - switch(c->_state) - { - case CALL_STATE_HOLD: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/hold.svg", NULL); - break; - case CALL_STATE_INCOMING: - case CALL_STATE_RINGING: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/ring.svg", NULL); - break; - case CALL_STATE_CURRENT: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/current.svg", NULL); - break; - case CALL_STATE_DIALING: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/dial.svg", NULL); - break; - case CALL_STATE_FAILURE: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/fail.svg", NULL); - break; - case CALL_STATE_BUSY: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/busy.svg", NULL); - break; - case CALL_STATE_TRANSFERT: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/transfert.svg", NULL); - break; - case CALL_STATE_RECORD: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/rec_call.svg", NULL); - break; - default: - WARN("Update calltree - Should not happen!"); - } + if (pixbuf != NULL) + g_object_unref(G_OBJECT(pixbuf)); - switch(c->_srtp_state) - { - case SRTP_STATE_SAS_UNCONFIRMED: - DEBUG("Secure is ON"); - pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_unconfirmed.svg", NULL); - if(c->_sas != NULL) { DEBUG("SAS is ready with value %s", c->_sas); } - break; - case SRTP_STATE_SAS_CONFIRMED: - DEBUG("SAS is confirmed"); - pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_confirmed.svg", NULL); - break; - case SRTP_STATE_SAS_SIGNED: - DEBUG("Secure is ON with SAS signed and verified"); - pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_certified.svg", NULL); - break; - case SRTP_STATE_UNLOCKED: - DEBUG("Secure is off calltree %d", c->_state); - if(g_strcasecmp(srtp_enabled,"true") == 0) { - pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_off.svg", NULL); - } - break; - default: - WARN("Update calltree srtp state #%d- Should not happen!", c->_srtp_state); - if(g_strcasecmp(srtp_enabled,"true") == 0) { - pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_off.svg", NULL); - } - } - } - else - { - switch(c->_history_state) - { - case OUTGOING: - DEBUG("Outgoing state"); - pixbuf = gdk_pixbuf_new_from_file( ICONS_DIR "/outgoing.svg", NULL); - break; - case INCOMING: - DEBUG("Incoming state"); - pixbuf = gdk_pixbuf_new_from_file( ICONS_DIR "/incoming.svg", NULL); - break; - case MISSED: - DEBUG("Missed state"); - pixbuf = gdk_pixbuf_new_from_file( ICONS_DIR "/missed.svg", NULL); - break; - default: - DEBUG("No history state"); - break; - } - date = get_formatted_start_timestamp (c); - duration = get_call_duration (c); - duration = g_strconcat( date , duration , NULL); - description = g_strconcat( description , duration, NULL); - } - - //Resize it - if(pixbuf != NULL) - { - if(gdk_pixbuf_get_width(pixbuf) > 32 || gdk_pixbuf_get_height(pixbuf) > 32) - { - pixbuf = gdk_pixbuf_scale_simple(pixbuf, 32, 32, GDK_INTERP_BILINEAR); - } - } - - if(pixbuf_security != NULL) - { - if(gdk_pixbuf_get_width(pixbuf_security) > 32 || gdk_pixbuf_get_height(pixbuf_security) > 32) - { - pixbuf_security = gdk_pixbuf_scale_simple(pixbuf_security, 32, 32, GDK_INTERP_BILINEAR); } } - - gtk_list_store_set(store, &iter, - 0, pixbuf, // Icon - 1, description, // Description - 2, pixbuf_security, // Icon - -1); - - if (pixbuf != NULL) - { g_object_unref(G_OBJECT(pixbuf)); } - - if (pixbuf_security != NULL) - { g_object_unref(G_OBJECT(pixbuf_security)); } + } - toolbar_update_buttons(); } -void calltree_add_call (calltab_t* tab, callable_obj_t * c) + +void calltree_add_call (calltab_t* tab, callable_obj_t * c, GtkTreeIter *parent) { + + DEBUG("calltree_add_call %s", c->_callID); + if (tab == history) { calltree_add_history_entry (c); return; } + account_t* account_details=NULL; GdkPixbuf *pixbuf=NULL; @@ -587,11 +693,24 @@ void calltree_add_call (calltab_t* tab, callable_obj_t * c) gchar * description; gchar * date=""; gchar *duration=""; - description = g_markup_printf_escaped("<b>%s</b> <i>%s</i>", - c->_peer_number, - c->_peer_name); - gtk_list_store_prepend (tab->store, &iter); + if(c->_state_code == 0) { + + description = g_markup_printf_escaped("<b>%s</b> <i>%s</i>", + c->_peer_number, + c->_peer_name); + + } + else { + + description = g_markup_printf_escaped("<b>%s</b> <i>%s</i>\n<i>%s (%d)</i>", + c->_peer_number, + c->_peer_name, + c->_state_code_description, + c->_state_code); + } + + gtk_tree_store_prepend (tab->store, &iter, parent); if(c != NULL) { account_details = account_list_get_by_id(c->_callID); @@ -662,13 +781,12 @@ void calltree_add_call (calltab_t* tab, callable_obj_t * c) } } - gtk_list_store_set(tab->store, &iter, - 0, pixbuf, // Icon - 1, description, // Description - 2, pixbuf_security, // Informs user about the state of security - 3, c, // Pointer - -1); - + gtk_tree_store_set(tab->store, &iter, + 0, pixbuf, // Icon + 1, description, // Description + 2, pixbuf_security, // Informs user about the state of security + 3, c, // Pointer + -1); if (pixbuf != NULL) { g_object_unref(G_OBJECT(pixbuf)); } @@ -685,6 +803,8 @@ void calltree_add_call (calltab_t* tab, callable_obj_t * c) void calltree_add_history_entry (callable_obj_t * c) { + DEBUG("calltree_add_history_entry %s", c->_callID); + if ( g_strcasecmp (dbus_get_history_enabled (), "false") == 0) return; @@ -698,7 +818,7 @@ void calltree_add_history_entry (callable_obj_t * c) c->_peer_number, c->_peer_name); - gtk_list_store_prepend (history->store, &iter); + gtk_tree_store_prepend (history->store, &iter, NULL); switch(c->_history_state) { @@ -738,7 +858,7 @@ void calltree_add_history_entry (callable_obj_t * c) pixbuf_security = gdk_pixbuf_scale_simple(pixbuf_security, 32, 32, GDK_INTERP_BILINEAR); } } - gtk_list_store_set(history->store, &iter, + gtk_tree_store_set(history->store, &iter, 0, pixbuf, // Icon 1, description, // Description 2, pixbuf_security, // Icon @@ -755,6 +875,270 @@ void calltree_add_history_entry (callable_obj_t * c) history_reinit(history); } + +void calltree_add_conference (calltab_t* tab, conference_obj_t* conf) +{ + + DEBUG("calltree_add_conference conf->_confID %s\n", conf->_confID); + + GdkPixbuf *pixbuf=NULL; + GdkPixbuf *pixbuf_security=NULL; + GtkTreeIter iter; + GtkTreePath *path; + GtkTreeModel *model = (GtkTreeModel*)active_calltree->store; + + gchar** participant = (gchar**)dbus_get_participant_list(conf->_confID); + gchar** pl; + gchar* call_id; + + callable_obj_t * call; + + account_t* account_details=NULL; + gchar* srtp_enabled=""; + + // New call in the list + + gchar * description; + // description = g_markup_printf_escaped("<b>%s</b>", conf->_confID); + description = g_markup_printf_escaped("<b>%s</b>", ""); + + gtk_tree_store_append (tab->store, &iter, NULL); + + if( tab == current_calls ) + { + switch(conf->_state) + { + case CONFERENCE_STATE_ACTIVE_ATACHED: + { + + pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/usersActive.svg", NULL); + break; + } + case CONFERENCE_STATE_ACTIVE_DETACHED: + case CONFERENCE_STATE_HOLD: + { + + + pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/users.svg", NULL); + break; + } + default: + WARN("Update conference add - Should not happen!"); + } + + } + + else { + WARN ("Conferences cannot be added in this widget - This is a bug in the application."); + } + + //Resize it + if(pixbuf) + { + if(gdk_pixbuf_get_width(pixbuf) > 32 || gdk_pixbuf_get_height(pixbuf) > 32) + { + pixbuf = gdk_pixbuf_scale_simple(pixbuf, 32, 32, GDK_INTERP_BILINEAR); + } + } + else + { + DEBUG("Error no pixbuff for conference from %s", ICONS_DIR); + } + + + // Used to determine if at least one participant use a security feature + // If true (at least on call use a security feature) we need to display security icons + conf->_conf_srtp_enabled = FALSE; + + // Used to determine if the conference is secured + // Every participant to a conference must be secured, the conference is not secured elsewhere + conf->_conference_secured = TRUE; + + + participant = (gchar**)dbus_get_participant_list(conf->_confID); + if(participant) + { + participant = (gchar**)dbus_get_participant_list(conf->_confID); + for (pl = participant; *participant; participant++) + { + call_id = (gchar*)(*participant); + call = calllist_get (tab, call_id); + + if(call != NULL) { + + account_details = account_list_get_by_id(call->_callID); + if(account_details != NULL) { + srtp_enabled = g_hash_table_lookup(account_details->properties, ACCOUNT_SRTP_ENABLED); + } + + if(g_strcasecmp(srtp_enabled,"true") == 0) { + conf->_conf_srtp_enabled = TRUE; + break; + } + + + } + + } + + if(conf->_conf_srtp_enabled) + { + participant = (gchar**)dbus_get_participant_list(conf->_confID); + for (pl = participant; *participant; participant++) + { + call_id = (gchar*)(*participant); + call = calllist_get (tab, call_id); + + if(call != NULL) { + + if(call->_srtp_state == 0) + { + conf->_conference_secured = FALSE; + break; + } + } + } + } + } + + if(conf->_conf_srtp_enabled) + { + if(conf->_conference_secured) + { + pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_confirmed.svg", NULL); + } + else + { + pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_off.svg", NULL); + } + } + + DEBUG("add conference to tree store"); + + gtk_tree_store_set(tab->store, &iter, + 0, pixbuf, // Icon + 1, description, // Description + 2, pixbuf_security, + 3, conf, // Pointer + -1); + + DEBUG("add conference to tree store"); + + + if (pixbuf != NULL) + g_object_unref(G_OBJECT(pixbuf)); + + + participant = (gchar**)dbus_get_participant_list(conf->_confID); + if(participant) + { + for (pl = participant; *participant; participant++) + { + + + call_id = (gchar*)(*participant); + call = calllist_get (tab, call_id); + // create_new_call_from_details (conf_id, conference_details, &c); + + calltree_remove_call(tab, call, NULL); + calltree_add_call (tab, call, &iter); + } + } + + gtk_tree_view_set_model(GTK_TREE_VIEW(tab->view), GTK_TREE_MODEL(tab->store)); + + path = gtk_tree_model_get_path(model, &iter); + + gtk_tree_view_expand_row(GTK_TREE_VIEW(tab->view), path, FALSE); + + toolbar_update_buttons(); + +} + + +void calltree_update_conference (calltab_t* tab, const gchar* confID) +{ + + DEBUG("calltree_update_conference"); + + +} + + +void calltree_remove_conference (calltab_t* tab, const conference_obj_t* conf, GtkTreeIter *parent) +{ + + DEBUG("calltree_remove_conference %s\n", conf->_confID); + + GtkTreeIter iter_parent; + GtkTreeIter iter_child; + GValue confval; + GValue callval; + conference_obj_t * tempconf; + callable_obj_t * call; + GtkTreeStore* store = tab->store; + + int nbChild = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), parent); + + int nbParticipant; + + int i, j; + for( i = 0; i < nbChild; i++) + { + + if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter_parent, parent, i)) + { + + if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter_parent)) + { + + calltree_remove_conference (tab, conf, &iter_parent); + + confval.g_type = 0; + gtk_tree_model_get_value (GTK_TREE_MODEL(store), &iter_parent, COLUMN_ACCOUNT_PTR, &confval); + + tempconf = (conference_obj_t*) g_value_get_pointer(&confval); + g_value_unset(&confval); + + if(tempconf == conf) + { + nbParticipant = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), &iter_parent); + DEBUG("nbParticipant: %i\n", nbParticipant); + for( j = 0; j < nbParticipant; j++) + { + call = NULL; + if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter_child, &iter_parent, j)) + { + + callval.g_type = 0; + gtk_tree_model_get_value (GTK_TREE_MODEL(store), &iter_child, COLUMN_ACCOUNT_PTR, &callval); + + call = (callable_obj_t*)g_value_get_pointer(&callval); + g_value_unset(&callval); + + if(call) + { + calltree_add_call (tab, call, NULL); + } + } + + } + + gtk_tree_store_remove(store, &iter_parent); + } + } + } + } + + // callable_obj_t * selectedCall = calltab_get_selected_call(tab); + // if(selectedCall == c) + // calltab_select_call(tab, NULL); + + toolbar_update_buttons(); + +} + + void calltree_display (calltab_t *tab) { @@ -813,3 +1197,297 @@ void calltree_display (calltab_t *tab) { g_signal_emit_by_name(sel, "changed"); toolbar_update_buttons(); } + + + + +static void drag_begin_cb(GtkWidget *widget, GdkDragContext *dc, gpointer data) +{ + + GtkTargetList* target_list; + + // g_print("drag_begin_cb %s\n", dragged_path); + if((target_list = gtk_drag_source_get_target_list(widget)) != NULL); + + +} + +static void drag_end_cb(GtkWidget * widget, GdkDragContext * context, gpointer data) +{ + DEBUG("drag_end_cb\n"); + DEBUG(" selected_path %s, selected_call_id %s, selected_path_depth %i\n", selected_path, selected_call_id, selected_path_depth); + DEBUG(" dragged path %s, dragged_call_id %s, dragged_path_depth %i\n", selected_path, selected_call_id, dragged_path_depth); + + GtkTreeModel* model = (GtkTreeModel*)current_calls->store; + GtkTreePath *path = gtk_tree_path_new_from_string(dragged_path); + GtkTreePath *dpath = gtk_tree_path_new_from_string(dragged_path); + GtkTreePath *spath = gtk_tree_path_new_from_string(selected_path); + + GtkTreeIter iter; + GtkTreeIter iter_parent; + GtkTreeIter iter_children; + GtkTreeIter parent_conference; + + GValue val; + + conference_obj_t* conf; + + + if(selected_path_depth == 1) + { + if(dragged_path_depth == 1) + { + + if (selected_type == A_CALL && dragged_type == A_CALL) + { + + if(gtk_tree_path_compare (dpath, spath) == 0) + { + // draged a call on itself + } + else + { + // dragged a single call on a single call + if(selected_call != NULL && dragged_call != NULL) + sflphone_join_participant(selected_call->_callID, dragged_call->_callID); + } + } + else if(selected_type == A_CALL && dragged_type == A_CONFERENCE) + { + // dragged a single call on a conference + sflphone_add_participant(selected_call_id, dragged_call_id); + } + else if(selected_type == A_CONFERENCE && dragged_type == A_CALL) + { + // dragged a conference on a single call (make no sence) + calltree_remove_conference(current_calls, selected_conf, NULL); + calltree_add_conference(current_calls, selected_conf); + + + } + else if(selected_type == A_CONFERENCE && dragged_type == A_CONFERENCE) + { + // dragged a conference on a conference + if(gtk_tree_path_compare (dpath, spath) == 0) + { + DEBUG("Joined the same conference!\n"); + gtk_tree_view_expand_row(GTK_TREE_VIEW(current_calls->view), path, FALSE); + } + else + { + DEBUG("Joined two conference %s, %s!\n", dragged_path, selected_path); + sflphone_join_conference(selected_conf->_confID, dragged_conf->_confID); + } + } + + // TODO: dragged a single call on a NULL element (should do nothing) + // TODO: dragged a conference on a NULL element (should do nothing) + + } + else // dragged_path_depth == 2 + { + if (selected_type == A_CALL && dragged_type == A_CALL) + { + // TODO: dragged a call on a conference call + calltree_remove_call(current_calls, selected_call, NULL); + calltree_add_call(current_calls, selected_call, NULL); + } + else if(selected_type == A_CONFERENCE && dragged_type == A_CALL) + { + // TODO: dragged a conference on a conference call + calltree_remove_conference(current_calls, selected_conf, NULL); + calltree_add_conference(current_calls, selected_conf); + } + + // TODO: dragged a single call on a NULL element + // TODO: dragged a conference on a NULL element + } + } + else // selected_path_depth == 2 + { + + if(dragged_path_depth == 1) + { + + if(selected_type == A_CALL && dragged_type == A_CALL) + { + + // dragged a conference call on a call + sflphone_detach_participant(selected_call_id); + + if(selected_call != NULL && dragged_call != NULL) + sflphone_join_participant(selected_call->_callID, dragged_call->_callID); + + } + else if(selected_type == A_CALL && dragged_type == A_CONFERENCE) + { + // dragged a conference call on a conference + sflphone_detach_participant(selected_call_id); + + if(selected_call != NULL && dragged_conf != NULL) + { + DEBUG("Adding a participant, since dragged call on a conference"); + + sflphone_add_participant(selected_call_id, dragged_call_id); + } + } + else + { + // dragged a conference call on a NULL element + sflphone_detach_participant(selected_call_id); + } + + } + else // dragged_path_depth == 2 + { + // dragged a conference call on another conference call (same conference) + // TODO: dragged a conference call on another conference call (different conference) + + gtk_tree_path_up(path); + + gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &parent_conference, path); + + gtk_tree_path_up(dpath); + gtk_tree_path_up(spath); + + if(gtk_tree_path_compare (dpath, spath) == 0) + { + + DEBUG("Dragged a call in the same conference"); + calltree_remove_call (current_calls, selected_call, NULL); + calltree_add_call (current_calls, selected_call, &parent_conference); + } + else + { + DEBUG("Dragged a conference call onto another conference call %s, %s", gtk_tree_path_to_string(dpath), gtk_tree_path_to_string(spath)); + + conf = NULL; + + val.g_type = 0; + if(gtk_tree_model_get_iter (model, &iter, dpath)) + { + DEBUG("we got an iter!"); + gtk_tree_model_get_value (model, &iter, COLUMN_ACCOUNT_PTR, &val); + + conf = (conference_obj_t*)g_value_get_pointer(&val); + } + g_value_unset(&val); + + sflphone_detach_participant(selected_call_id); + + if(conf) + { + DEBUG("we got a conf!"); + sflphone_add_participant(selected_call_id, conf->_confID); + } + else + { + DEBUG("didn't find a conf!"); + } + } + + + // TODO: dragged a conference call on another conference call (different conference) + // TODO: dragged a conference call on a NULL element (same conference) + // TODO: dragged a conference call on a NULL element (different conference) + } + + } + +} + + +void drag_data_received_cb(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t, gpointer data) +{ + + // g_print("drag_data_received_cb\n"); + GtkTreeView *tree_view = GTK_TREE_VIEW(widget); + GtkTreePath *drop_path; + GtkTreeViewDropPosition position; + GValue val; + + GtkTreeModel *model = (GtkTreeModel*)active_calltree->store; + GtkTreeModel* tree_model = gtk_tree_view_get_model(tree_view); + + GtkTreeIter iter; + gchar value; + + + val.g_type = 0; + gtk_tree_view_get_drag_dest_row(tree_view, &drop_path, &position); + + if(drop_path) + { + + gtk_tree_model_get_iter(tree_model, &iter, drop_path); + gtk_tree_model_get_value(tree_model, &iter, COLUMN_ACCOUNT_PTR, &val); + + + if(gtk_tree_model_iter_has_child(tree_model, &iter)) + { + DEBUG("DRAGGING ON A CONFERENCE"); + dragged_type = A_CONFERENCE; + } + else + { + DEBUG("DRAGGING ON A CALL"); + dragged_type = A_CALL; + } + + switch (position) + { + case GTK_TREE_VIEW_DROP_AFTER: + dragged_path = gtk_tree_path_to_string(drop_path); + dragged_path_depth = gtk_tree_path_get_depth(drop_path); + dragged_call_id = "NULL"; + dragged_call = NULL; + dragged_conf = NULL; + g_print(" AFTER dragged_path %s, dragged_call_id %s, dragged_path_depth %i\n", dragged_path, dragged_call_id, dragged_path_depth); + break; + + case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: + dragged_path = gtk_tree_path_to_string(drop_path); + dragged_path_depth = gtk_tree_path_get_depth(drop_path); + if (dragged_type == A_CALL) + { + dragged_call_id = ((callable_obj_t*)g_value_get_pointer(&val))->_callID; + dragged_call = (callable_obj_t*)g_value_get_pointer(&val); + } + else + { + dragged_call_id = ((conference_obj_t*)g_value_get_pointer(&val))->_confID; + dragged_conf = (conference_obj_t*)g_value_get_pointer(&val); + } + g_print(" INTO_OR_AFTER dragged_path %s, dragged_call_id %s, dragged_path_depth %i\n", dragged_path, dragged_call_id, dragged_path_depth); + break; + + case GTK_TREE_VIEW_DROP_BEFORE: + dragged_path = gtk_tree_path_to_string(drop_path); + dragged_path_depth = gtk_tree_path_get_depth(drop_path); + dragged_call_id = "NULL"; + dragged_call = NULL; + dragged_conf = NULL; + g_print(" BEFORE dragged_path %s, dragged_call_id %s, dragged_path_depth %i\n", dragged_path, dragged_call_id, dragged_path_depth); + break; + + case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: + dragged_path = gtk_tree_path_to_string(drop_path); + dragged_path_depth = gtk_tree_path_get_depth(drop_path); + if (dragged_type == A_CALL) + { + dragged_call_id = ((callable_obj_t*)g_value_get_pointer(&val))->_callID; + dragged_call = (callable_obj_t*)g_value_get_pointer(&val); + } + else + { + dragged_call_id = ((conference_obj_t*)g_value_get_pointer(&val))->_confID; + dragged_conf = (conference_obj_t*)g_value_get_pointer(&val); + } + g_print(" INTO_OR_BEFORE dragged_path %s, dragged_call_id %s, dragged_path_depth %i\n", dragged_path, dragged_call_id, dragged_path_depth); + break; + + default: + return; + } + } +} diff --git a/sflphone-client-gnome/src/contacts/calltree.h b/sflphone-client-gnome/src/contacts/calltree.h index ca8fa76cf08cfc2bae30c1385a91ca861a0fb718..a01565bc4b29f245bf94c745d5780f9bfd4647ce 100644 --- a/sflphone-client-gnome/src/contacts/calltree.h +++ b/sflphone-client-gnome/src/contacts/calltree.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2007 Savoir-Faire Linux inc. * Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com> + * Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,6 +34,12 @@ * @brief The GtkTreeView that list calls in the main window. */ +enum +{ + A_CALL, + A_CONFERENCE +}; + /** * Create a new widget calltree * @return GtkWidget* A new widget @@ -45,21 +52,33 @@ calltree_create(calltab_t* tab, gboolean searchbar_type); * @param c The call to add */ void -calltree_add_call (calltab_t* ct, callable_obj_t * c); +calltree_add_call (calltab_t* ct, callable_obj_t * c, GtkTreeIter *parent); /* * Update the call tree if the call state changes * @param c The call to update */ void -calltree_update_call (calltab_t* ct, callable_obj_t * c); +calltree_update_call (calltab_t* ct, callable_obj_t * c, GtkTreeIter *parent); /** * Remove a call from the call tree * @param c The call to remove */ void -calltree_remove_call (calltab_t* ct, callable_obj_t * c); +calltree_remove_call (calltab_t* ct, callable_obj_t * c, GtkTreeIter *parent); + +void +calltree_add_history_entry (callable_obj_t * c); + +void +calltree_add_conference (calltab_t* tab, conference_obj_t* conf); + +void +calltree_update_conference (calltab_t* tab, const gchar* confID); + +void +calltree_remove_conference (calltab_t* tab, const conference_obj_t* conf, GtkTreeIter *parent); void calltree_reset (calltab_t* tab); diff --git a/sflphone-client-gnome/src/contacts/conferencelist.c b/sflphone-client-gnome/src/contacts/conferencelist.c new file mode 100644 index 0000000000000000000000000000000000000000..9dee60e481f979646486623414c20a86f5122d42 --- /dev/null +++ b/sflphone-client-gnome/src/contacts/conferencelist.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2007 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <conferencelist.h> + + +gchar* +generate_conf_id (void) +{ + gchar *conf_id; + + conf_id = g_new0(gchar, 30); + g_sprintf(conf_id, "%d", rand()); + return conf_id; +} + + +void +conferencelist_init() +{ + conferenceQueue = g_queue_new (); +} + + +void +conferencelist_clean() +{ + g_queue_free (conferenceQueue); +} + + +void +conferencelist_reset() +{ + g_queue_free (conferenceQueue); + conferenceQueue = g_queue_new(); +} + + +void +conferencelist_add(const conference_obj_t* conf) +{ + gchar* c = (gchar*)conferencelist_get(conf->_confID); + if(!c) + { + g_queue_push_tail (conferenceQueue, (gpointer)conf); + } +} + + +void +conferencelist_remove (const gchar* conf) +{ + gchar* c = (gchar*)conferencelist_get(conf); + if (c) + { + g_queue_remove(conferenceQueue, c); + } +} + +conference_obj_t* +conferencelist_get (const gchar* conf_id) +{ + + GList* c = g_queue_find_custom(conferenceQueue, conf_id, is_confID_confstruct); + if (c) + { + return (conference_obj_t*)c->data; + } + else + { + return NULL; + } +} + + +conference_obj_t* +conferencelist_get_nth ( guint n ) +{ + GList* c = g_queue_peek_nth(conferenceQueue, n); + if (c) + { + return (conference_obj_t*)c->data; + } + else + { + return NULL; + } +} + + +guint +conferencelist_get_size () +{ + return g_queue_get_length (conferenceQueue); +} diff --git a/sflphone-client-gnome/src/contacts/conferencelist.h b/sflphone-client-gnome/src/contacts/conferencelist.h new file mode 100644 index 0000000000000000000000000000000000000000..4836914f7a36008731935531366542eb2c1ce6f2 --- /dev/null +++ b/sflphone-client-gnome/src/contacts/conferencelist.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __CONFERENCELIST_H__ +#define __CONFERENCELIST_H__ + + +#include <conference_obj.h> +#include <gtk/gtk.h> + +/** @file conferencelist.h + * @brief A list to store conferences. + */ + +GQueue* conferenceQueue; + +/** This function initialize a conference list. */ +void +conferencelist_init (); + +/** This function empty and free the conference list. */ +void +conferencelist_clean (); + +/** This function empty, free the conference list and allocate a new one. */ +void +conferencelist_reset (); + +/** This function append a conference to the list. + * @param conf The conference you want to add + * */ +void +conferencelist_add (const conference_obj_t* conf); + +/** This function remove a conference from list. + * @param callID The callID of the conference you want to remove + */ +void +conferencelist_remove (const gchar* conf); + +/** Return the number of calls in the list + * @return The number of calls in the list */ +guint +conferencelist_get_size (); + +/** Return the call at the nth position in the list + * @param n The position of the call you want + * @return A call or NULL */ +conference_obj_t* +conferencelist_get_nth (guint n ); + +/** Return the call corresponding to the callID + * @param n The callID of the call you want + * @return A call or NULL */ +conference_obj_t* +conferencelist_get (const gchar* conf); + + +#endif diff --git a/sflphone-client-gnome/src/dbus/callmanager-introspec.xml b/sflphone-client-gnome/src/dbus/callmanager-introspec.xml index e8f6e1da08d10e37238fcd862727b1aa53ea5a35..ba4e42577b4b546a1cb001049cbe63622e491dda 100644 --- a/sflphone-client-gnome/src/dbus/callmanager-introspec.xml +++ b/sflphone-client-gnome/src/dbus/callmanager-introspec.xml @@ -19,6 +19,10 @@ <method name="hangUp"> <arg type="s" name="callID" direction="in"/> </method> + + <method name="hangUpConference"> + <arg type="s" name="confID" direction="in"/> + </method> <method name="hold"> <arg type="s" name="callID" direction="in"/> @@ -52,6 +56,39 @@ <arg type="d" name="value" direction="out"/> </method> + <method name="joinParticipant"> + <arg type="s" name="sel_callID" direction="in"/> + <arg type="s" name="drag_callID" direction="in"/> + </method> + + <method name="addParticipant"> + <arg type="s" name="callID" direction="in"/> + <arg type="s" name="confID" direction="in"/> + </method> + + <method name="addMainParticipant"> + <arg type="s" name="confID" direction="in"/> + </method> + + <method name="detachParticipant"> + <arg type="s" name="callID" direction="in"/> + </method> + + <method name="joinConference"> + <arg type="s" name="sel_confID" direction="in"/> + <arg type="s" name="drag_confID" direction="in"/> + </method> + + <method name="getConferenceDetails"> + <arg type="s" name="callID" direction="in"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="MapStringString"/> + <arg type="a{ss}" name="infos" direction="out"/> + </method> + + <method name="getConferenceList"> + <arg type="as" name="list" direction="out"/> + </method> + <method name="setRecording"> <arg type="s" name="callID" direction="in"/> </method> @@ -101,18 +138,43 @@ <arg type="s" name="state" direction="out"/> </signal> + <signal name="conferenceChanged"> + <arg type="s" name="confID" direction="out"/> + <arg type="s" name="state" direction="out"/> + </signal> + + <method name="getParticipantList"> + <arg type="s" name="confID" direction="in"/> + <arg type="as" name="list" direction="out"/> + </method> + + <signal name="conferenceCreated"> + <arg type="s" name="confID" direction="out"/> + </signal> + + <signal name="conferenceRemoved"> + <arg type="s" name="confID" direction="out"/> + </signal> + + <method name="holdConference"> + <arg type="s" name="confID" direction="in"/> + </method> + + <method name="unholdConference"> + <arg type="s" name="confID" direction="in"/> + </method> + <signal name="sipCallStateChanged"> <arg type="s" name="callID" direction="out"/> <arg type="s" name="state" direction="out"/> <arg type="i" name="code" direction="out"/> </signal> - + <signal name="voiceMailNotify"> <arg type="s" name="accountID" direction="out"/> <arg type="i" name="count" direction="out"/> </signal> - <signal name="volumeChanged"> <arg type="s" name="device" direction="out"/> <arg type="d" name="value" direction="out"/> @@ -169,7 +231,7 @@ <signal name="confirmGoClear"> <arg type="s" name="callID" direction="out" /> </signal> - + <!-- <signal name="error"> <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="MapStringString"/> diff --git a/sflphone-client-gnome/src/dbus/dbus.c b/sflphone-client-gnome/src/dbus/dbus.c index d02aed7446c241455899a6b7e6847f56c3825063..8a00188806bbf91413d08960d5a5bdb610a025a7 100644 --- a/sflphone-client-gnome/src/dbus/dbus.c +++ b/sflphone-client-gnome/src/dbus/dbus.c @@ -141,11 +141,11 @@ call_state_cb (DBusGProxy *proxy UNUSED, // peer hung up, the conversation was established, so _stop has been initialized with the current time value DEBUG("call state current"); set_timestamp (&c->_time_stop); - calltree_update_call( history, c ); + calltree_update_call( history, c, NULL); } stop_notification(); sflphone_hung_up (c); - calltree_update_call( history, c ); + calltree_update_call( history, c, NULL ); status_bar_display_account(); } else if ( strcmp(state, "UNHOLD_CURRENT") == 0 ) @@ -211,7 +211,7 @@ call_state_cb (DBusGProxy *proxy UNUSED, calllist_add (current_calls, new_call); calllist_add (history, new_call); - calltree_add_call (current_calls, new_call); + calltree_add_call (current_calls, new_call, NULL); update_menus (); calltree_display (current_calls); @@ -220,6 +220,68 @@ call_state_cb (DBusGProxy *proxy UNUSED, } } +static void +conference_changed_cb (DBusGProxy *proxy UNUSED, + const gchar* confID, + const gchar* state, + void * foo UNUSED ) +{ + DEBUG ("-------------------- Conference changed ---------------------\n"); + // sflphone_display_transfer_status("Transfer successfull"); + conference_obj_t* changed_conf = conferencelist_get(confID); + + DEBUG(" %s\n", state); + + if(changed_conf) + { + calltree_remove_conference (current_calls, changed_conf, NULL); + + if ( strcmp(state, "ACTIVE_ATACHED") == 0 ) + { + changed_conf->_state = CONFERENCE_STATE_ACTIVE_ATACHED; + } + else if ( strcmp(state, "ACTIVE_DETACHED") == 0 ) + { + changed_conf->_state = CONFERENCE_STATE_ACTIVE_DETACHED; + } + else if ( strcmp(state, "HOLD") == 0 ) + { + changed_conf->_state = CONFERENCE_STATE_HOLD; + } + + calltree_add_conference (current_calls, changed_conf); + } +} + + +static void +conference_created_cb (DBusGProxy *proxy UNUSED, + const gchar* confID, + void * foo UNUSED ) +{ + DEBUG ("Conference added %s\n", confID); + + conference_obj_t* new_conf; + + create_new_conference(CONFERENCE_STATE_ACTIVE_ATACHED, confID, &new_conf); + new_conf->_confID = g_strdup(confID); + conferencelist_add(new_conf); + calltree_add_conference (current_calls, new_conf); +} + + +static void +conference_removed_cb (DBusGProxy *proxy UNUSED, + const gchar* confID, + void * foo UNUSED ) +{ + DEBUG ("Conference removed %s\n", confID); + + conference_obj_t * c = conferencelist_get(confID); + calltree_remove_conference (current_calls, c, NULL); + conferencelist_remove(c->_confID); +} + static void accounts_changed_cb (DBusGProxy *proxy UNUSED, @@ -468,6 +530,25 @@ dbus_connect () dbus_g_proxy_connect_signal (callManagerProxy, "transferFailed", G_CALLBACK(transfer_failed_cb), NULL, NULL); + /* Conference related callback */ + + dbus_g_object_register_marshaller(g_cclosure_user_marshal_VOID__STRING, + G_TYPE_NONE, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_add_signal (callManagerProxy, + "conferenceChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (callManagerProxy, + "conferenceChanged", G_CALLBACK(conference_changed_cb), NULL, NULL); + + dbus_g_proxy_add_signal (callManagerProxy, + "conferenceCreated", G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (callManagerProxy, + "conferenceCreated", G_CALLBACK(conference_created_cb), NULL, NULL); + + dbus_g_proxy_add_signal (callManagerProxy, + "conferenceRemoved", G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (callManagerProxy, + "conferenceRemoved", G_CALLBACK(conference_removed_cb), NULL, NULL); + /* Security related callbacks */ /* Register a marshaller for STRING,STRING,BOOL */ @@ -504,6 +585,7 @@ dbus_connect () dbus_g_object_register_marshaller(g_cclosure_user_marshal_VOID__STRING_STRING_INT, G_TYPE_NONE, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INVALID); + dbus_g_proxy_add_signal (callManagerProxy, "sipCallStateChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INVALID); dbus_g_proxy_connect_signal (callManagerProxy, @@ -562,6 +644,8 @@ dbus_clean () void dbus_hold (const callable_obj_t * c) { + DEBUG("dbus_hold %s\n", c->_callID); + GError *error = NULL; org_sflphone_SFLphone_CallManager_hold ( callManagerProxy, c->_callID, &error); if (error) @@ -575,6 +659,8 @@ dbus_hold (const callable_obj_t * c) void dbus_unhold (const callable_obj_t * c) { + DEBUG("dbus_unhold %s\n", c->_callID); + GError *error = NULL; org_sflphone_SFLphone_CallManager_unhold ( callManagerProxy, c->_callID, &error); if (error) @@ -585,9 +671,41 @@ dbus_unhold (const callable_obj_t * c) } } + void +dbus_hold_conference (const conference_obj_t * c) +{ + DEBUG("dbus_hold_conference %s\n", c->_confID); + + GError *error = NULL; + org_sflphone_SFLphone_CallManager_hold_conference ( callManagerProxy, c->_confID, &error); + if (error) + { + ERROR ("Failed to call hold() on CallManager: %s", + error->message); + g_error_free (error); + } +} + + void +dbus_unhold_conference (const conference_obj_t * c) +{ + DEBUG("dbus_unhold_conference %s\n", c->_confID); + + GError *error = NULL; + org_sflphone_SFLphone_CallManager_unhold_conference ( callManagerProxy, c->_confID, &error); + if (error) + { + ERROR ("Failed to call unhold() on CallManager: %s", + error->message); + g_error_free (error); + } +} + void dbus_hang_up (const callable_obj_t * c) { + DEBUG("dbus_hang_up %s\n", c->_callID); + GError *error = NULL; org_sflphone_SFLphone_CallManager_hang_up ( callManagerProxy, c->_callID, &error); if (error) @@ -598,6 +716,22 @@ dbus_hang_up (const callable_obj_t * c) } } + + void +dbus_hang_up_conference (const conference_obj_t * c) +{ + DEBUG("dbus_hang_up_conference %s\n", c->_confID); + + GError *error = NULL; + org_sflphone_SFLphone_CallManager_hang_up_conference ( callManagerProxy, c->_confID, &error); + if (error) + { + ERROR ("Failed to call hang_up() on CallManager: %s", + error->message); + g_error_free (error); + } +} + void dbus_transfert (const callable_obj_t * c) { @@ -617,6 +751,9 @@ dbus_accept (const callable_obj_t * c) #if GTK_CHECK_VERSION(2,10,0) status_tray_icon_blink( FALSE ); #endif + + DEBUG("dbus_accept %s\n", c->_callID); + GError *error = NULL; org_sflphone_SFLphone_CallManager_accept ( callManagerProxy, c->_callID, &error); if (error) @@ -633,6 +770,9 @@ dbus_refuse (const callable_obj_t * c) #if GTK_CHECK_VERSION(2,10,0) status_tray_icon_blink( FALSE ); #endif + + DEBUG("dbus_refuse %s\n", c->_callID); + GError *error = NULL; org_sflphone_SFLphone_CallManager_refuse ( callManagerProxy, c->_callID, &error); if (error) @@ -647,6 +787,8 @@ dbus_refuse (const callable_obj_t * c) void dbus_place_call (const callable_obj_t * c) { + DEBUG("dbus_place_call %s\n", c->_callID); + GError *error = NULL; org_sflphone_SFLphone_CallManager_place_call ( callManagerProxy, c->_accountID, c->_callID, c->_peer_number, &error); if (error) @@ -1535,16 +1677,113 @@ dbus_set_volume_controls( ) } } +void +dbus_join_participant(const gchar* sel_callID, const gchar* drag_callID) +{ + + DEBUG("dbus_join_participant %s and %s\n", sel_callID, drag_callID); + + GError* error = NULL; + + org_sflphone_SFLphone_CallManager_join_participant ( + callManagerProxy, + sel_callID, + drag_callID, + &error); + if(error) + { + g_error_free(error); + } + +} + +void +dbus_add_participant(const gchar* callID, const gchar* confID) +{ + + DEBUG("dbus_add_participant %s and %s\n", callID, confID); + + GError* error = NULL; + + org_sflphone_SFLphone_CallManager_add_participant ( + callManagerProxy, + callID, + confID, + &error); + if(error) + { + g_error_free(error); + } + +} + +void +dbus_add_main_participant(const gchar* confID) +{ + DEBUG("dbus_add_participant %s\n", confID); + + GError* error = NULL; + + org_sflphone_SFLphone_CallManager_add_main_participant ( + callManagerProxy, + confID, + &error); + if(error) + { + g_error_free(error); + } +} + void -dbus_set_record(const callable_obj_t * c) +dbus_detach_participant(const gchar* callID) { - DEBUG("calling dbus_set_record on CallManager"); - DEBUG("CallID : %s", c->_callID); + + DEBUG("dbus_detach_participant %s\n", callID); + + GError* error = NULL; + org_sflphone_SFLphone_CallManager_detach_participant( + callManagerProxy, + callID, + &error); + if(error) + { + g_error_free(error); + } + +} + + +dbus_join_conference(const gchar* sel_confID, const gchar* drag_confID) +{ + + DEBUG("dbus_join_conference %s and %s\n", sel_confID, drag_confID); + + GError* error = NULL; + + org_sflphone_SFLphone_CallManager_join_conference ( + callManagerProxy, + sel_confID, + drag_confID, + &error); + if(error) + { + g_error_free(error); + } + +} + + + + void +dbus_set_record(const gchar* id) +{ + DEBUG("dbus_set_record %s\n", id); + GError* error = NULL; org_sflphone_SFLphone_CallManager_set_recording ( callManagerProxy, - c->_callID, + id, &error); if(error) { @@ -1552,10 +1791,11 @@ dbus_set_record(const callable_obj_t * c) } } + gboolean dbus_get_is_recording(const callable_obj_t * c) { - DEBUG("calling dbus_get_is_recording on CallManager"); + DEBUG("dbus_get_is_recording %s\n", c->_callID); GError* error = NULL; gboolean isRecording; org_sflphone_SFLphone_CallManager_get_is_recording ( @@ -2037,6 +2277,50 @@ gchar** dbus_get_call_list (void) return list; } +gchar** dbus_get_conference_list (void) +{ + GError *error = NULL; + gchar **list = NULL; + + org_sflphone_SFLphone_CallManager_get_conference_list (callManagerProxy, &list, &error); + if (error){ + ERROR ("Error calling org_sflphone_SFLphone_CallManager_get_conference_list"); + g_error_free (error); + } + + return list; +} + + +gchar** dbus_get_participant_list (const char * confID) +{ + GError *error = NULL; + gchar **list = NULL; + + org_sflphone_SFLphone_CallManager_get_participant_list (callManagerProxy, confID, &list, &error); + if (error){ + ERROR ("Error calling org_sflphone_SFLphone_CallManager_get_participant_list"); + g_error_free (error); + } + + return list; +} + + +GHashTable* dbus_get_conference_details (const gchar *confID) +{ + GError *error = NULL; + GHashTable *details = NULL; + + org_sflphone_SFLphone_CallManager_get_conference_details (callManagerProxy, confID, &details, &error); + if (error){ + ERROR ("Error calling org_sflphone_SFLphone_CallManager_get_conference_details"); + g_error_free (error); + } + + return details; +} + void dbus_set_accounts_order (const gchar* order) { GError *error = NULL; diff --git a/sflphone-client-gnome/src/dbus/dbus.h b/sflphone-client-gnome/src/dbus/dbus.h index 58e977d6f1cffc0b70c8eb7450006f8804bffb41..123322b2816652ce28162c92c78fdf04031fab46 100644 --- a/sflphone-client-gnome/src/dbus/dbus.h +++ b/sflphone-client-gnome/src/dbus/dbus.h @@ -27,6 +27,8 @@ #include <accountlist.h> #include <calllist.h> +#include <conferencelist.h> +#include <conference_obj.h> #include <sflnotify.h> /** @file dbus.h @@ -518,7 +520,9 @@ void dbus_set_stun_server( gchar* server); gint dbus_stun_is_enabled (void); void dbus_enable_stun (void); -void dbus_set_record (const callable_obj_t * c); +void dbus_add_participant(const gchar* callID, const gchar* confID); + +void dbus_set_record (const gchar * id); void dbus_set_record_path (const gchar *path); gchar* dbus_get_record_path (void); diff --git a/sflphone-client-gnome/src/menus.c b/sflphone-client-gnome/src/menus.c index 0039d9dc22d1eae0c67bbc7911dd063e446ef665..cac13584d57296bf57f628ac2a7fbed4f459dfb1 100644 --- a/sflphone-client-gnome/src/menus.c +++ b/sflphone-client-gnome/src/menus.c @@ -254,6 +254,34 @@ call_hold (void* foo UNUSED) } } + static void +conference_hold (void* foo UNUSED) +{ + conference_obj_t * selectedConf = calltab_get_selected_conf(); + + switch(selectedConf->_state) + { + case CONFERENCE_STATE_HOLD: + { + gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM ( holdMenu ), gtk_image_new_from_file( ICONS_DIR "/icon_unhold.svg")); + selectedConf->_state = CONFERENCE_STATE_ACTIVE_ATACHED; + sflphone_conference_off_hold(selectedConf); + } + break; + + case CONFERENCE_STATE_ACTIVE_ATACHED: + case CONFERENCE_STATE_ACTIVE_DETACHED: + { + gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM ( holdMenu ), gtk_image_new_from_file( ICONS_DIR "/icon_hold.svg")); + selectedConf->_state = CONFERENCE_STATE_HOLD; + sflphone_conference_on_hold(selectedConf); + } + break; + default: + break; + } +} + static void call_pick_up ( void * foo UNUSED) { @@ -266,6 +294,12 @@ call_hang_up ( void * foo UNUSED) sflphone_hang_up(); } + static void +conference_hang_up ( void * foo UNUSED) +{ + sflphone_conference_hang_up(); +} + static void call_record ( void * foo UNUSED) { @@ -302,7 +336,7 @@ call_back( void * foo UNUSED) create_new_call (CALL, CALL_STATE_DIALING, "", "", selected_call->_peer_name, selected_call->_peer_number, &new_call); calllist_add(current_calls, new_call); - calltree_add_call(current_calls, new_call); + calltree_add_call(current_calls, new_call, NULL); sflphone_place_call(new_call); calltree_display (current_calls); } @@ -469,7 +503,7 @@ edit_paste ( void * foo UNUSED) { selectedCall->_peer_info = g_strconcat("\"\" <", selectedCall->_peer_number, ">", NULL); } - calltree_update_call(current_calls, selectedCall); + calltree_update_call(current_calls, selectedCall, NULL); } break; case CALL_STATE_RINGING: @@ -486,7 +520,7 @@ edit_paste ( void * foo UNUSED) selectedCall->_peer_info = g_strconcat("\"\" <", selectedCall->_peer_number, ">", NULL); - calltree_update_call(current_calls, selectedCall); + calltree_update_call(current_calls, selectedCall, NULL); } break; case CALL_STATE_CURRENT: @@ -502,7 +536,7 @@ edit_paste ( void * foo UNUSED) gchar * temp = g_strconcat(selectedCall->_peer_number, oneNo, NULL); selectedCall->_peer_info = get_peer_info (temp, selectedCall->_peer_name); // g_free(temp); - calltree_update_call(current_calls, selectedCall); + calltree_update_call(current_calls, selectedCall, NULL); } } @@ -521,7 +555,7 @@ edit_paste ( void * foo UNUSED) g_free(selectedCall->_peer_info); selectedCall->_peer_info = g_strconcat("\"\" <", selectedCall->_peer_number, ">", NULL); - calltree_update_call(current_calls,selectedCall); + calltree_update_call(current_calls, selectedCall, NULL); } } @@ -706,45 +740,87 @@ show_popup_menu (GtkWidget *my_widget, GdkEventButton *event) { // TODO update the selection to make sure the call under the mouse is the call selected - gboolean pickup = FALSE, hangup = FALSE, hold = FALSE, copy = FALSE, record = FALSE; + // call type boolean + gboolean pickup = FALSE, hangup = FALSE, hold = FALSE, copy = FALSE, record = FALSE, detach = FALSE; gboolean accounts = FALSE; - callable_obj_t * selectedCall = calltab_get_selected_call(current_calls); - if (selectedCall) + // conference type boolean + gboolean hangup_conf = FALSE, hold_conf = FALSE; + + callable_obj_t * selectedCall; + conference_obj_t * selectedConf; + + if (calltab_get_selected_type(current_calls) == A_CALL) { - copy = TRUE; - switch(selectedCall->_state) - { - case CALL_STATE_INCOMING: - pickup = TRUE; - hangup = TRUE; - break; - case CALL_STATE_HOLD: - hangup = TRUE; - hold = TRUE; - break; - case CALL_STATE_RINGING: - hangup = TRUE; - break; - case CALL_STATE_DIALING: - pickup = TRUE; - hangup = TRUE; - accounts = TRUE; - break; - case CALL_STATE_RECORD: - case CALL_STATE_CURRENT: - hangup = TRUE; - hold = TRUE; - record = TRUE; - break; - case CALL_STATE_BUSY: - case CALL_STATE_FAILURE: - hangup = TRUE; - break; - default: - WARN("Should not happen in show_popup_menu!"); - break; - } + DEBUG("MENUS: SELECTED A CALL"); + selectedCall = calltab_get_selected_call(current_calls); + + if (selectedCall) + { + copy = TRUE; + switch(selectedCall->_state) + { + case CALL_STATE_INCOMING: + pickup = TRUE; + hangup = TRUE; + detach = TRUE; + break; + case CALL_STATE_HOLD: + hangup = TRUE; + hold = TRUE; + detach = TRUE; + break; + case CALL_STATE_RINGING: + hangup = TRUE; + detach = TRUE; + break; + case CALL_STATE_DIALING: + pickup = TRUE; + hangup = TRUE; + accounts = TRUE; + break; + case CALL_STATE_RECORD: + case CALL_STATE_CURRENT: + hangup = TRUE; + hold = TRUE; + record = TRUE; + detach = TRUE; + break; + case CALL_STATE_BUSY: + case CALL_STATE_FAILURE: + hangup = TRUE; + break; + default: + WARN("Should not happen in show_popup_menu for calls!"); + break; + } + } + } + else + { + DEBUG("MENUS: SELECTED A CONF"); + selectedConf = calltab_get_selected_conf(); + + if (selectedConf) + { + switch(selectedConf->_state) + { + case CONFERENCE_STATE_ACTIVE_ATACHED: + hangup_conf = TRUE; + hold_conf = TRUE; + break; + case CONFERENCE_STATE_ACTIVE_DETACHED: + break; + case CONFERENCE_STATE_HOLD: + hangup_conf = TRUE; + hold_conf = TRUE; + break; + default: + WARN("Should not happen in show_popup_menu for conferences!"); + break; + } + } + } GtkWidget *menu; @@ -755,94 +831,127 @@ show_popup_menu (GtkWidget *my_widget, GdkEventButton *event) menu = gtk_menu_new (); //g_signal_connect (menu, "deactivate", // G_CALLBACK (gtk_widget_destroy), NULL); - - if(copy) + if (calltab_get_selected_type(current_calls) == A_CALL) { - menu_items = gtk_image_menu_item_new_from_stock( GTK_STOCK_COPY, get_accel_group()); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); - g_signal_connect (G_OBJECT (menu_items), "activate", - G_CALLBACK (edit_copy), - NULL); - gtk_widget_show (menu_items); - } - - menu_items = gtk_image_menu_item_new_from_stock( GTK_STOCK_PASTE, get_accel_group()); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); - g_signal_connect (G_OBJECT (menu_items), "activate", - G_CALLBACK (edit_paste), - NULL); - gtk_widget_show (menu_items); - - if(pickup || hangup || hold) - { - menu_items = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); - gtk_widget_show (menu_items); - } - - if(pickup) - { - - menu_items = gtk_image_menu_item_new_with_mnemonic(_("_Pick up")); - image = gtk_image_new_from_file( ICONS_DIR "/icon_accept.svg"); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_items), image); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); - g_signal_connect (G_OBJECT (menu_items), "activate", - G_CALLBACK (call_pick_up), - NULL); - gtk_widget_show (menu_items); - } - - if(hangup) - { - menu_items = gtk_image_menu_item_new_with_mnemonic(_("_Hang up")); - image = gtk_image_new_from_file( ICONS_DIR "/icon_hangup.svg"); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_items), image); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); - g_signal_connect (G_OBJECT (menu_items), "activate", - G_CALLBACK (call_hang_up), - NULL); - gtk_widget_show (menu_items); - } + DEBUG("BUILD CALL MENU"); + + if(copy) + { + menu_items = gtk_image_menu_item_new_from_stock( GTK_STOCK_COPY, get_accel_group()); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); + g_signal_connect (G_OBJECT (menu_items), "activate", + G_CALLBACK (edit_copy), + NULL); + gtk_widget_show (menu_items); + } + + menu_items = gtk_image_menu_item_new_from_stock( GTK_STOCK_PASTE, get_accel_group()); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); + g_signal_connect (G_OBJECT (menu_items), "activate", + G_CALLBACK (edit_paste), + NULL); + gtk_widget_show (menu_items); + + if(pickup || hangup || hold) + { + menu_items = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); + gtk_widget_show (menu_items); + } + + if(pickup) + { + + menu_items = gtk_image_menu_item_new_with_mnemonic(_("_Pick up")); + image = gtk_image_new_from_file( ICONS_DIR "/icon_accept.svg"); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_items), image); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); + g_signal_connect (G_OBJECT (menu_items), "activate", + G_CALLBACK (call_pick_up), + NULL); + gtk_widget_show (menu_items); + } + + if(hangup) + { + menu_items = gtk_image_menu_item_new_with_mnemonic(_("_Hang up")); + image = gtk_image_new_from_file( ICONS_DIR "/icon_hangup.svg"); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_items), image); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); + g_signal_connect (G_OBJECT (menu_items), "activate", + G_CALLBACK (call_hang_up), + NULL); + gtk_widget_show (menu_items); + } + + if(hold) + { + menu_items = gtk_check_menu_item_new_with_mnemonic (_("On _Hold")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_items), + (selectedCall->_state == CALL_STATE_HOLD ? TRUE : FALSE)); + g_signal_connect(G_OBJECT (menu_items), "activate", + G_CALLBACK (call_hold), + NULL); + gtk_widget_show (menu_items); + } + + if(record) + { + menu_items = gtk_image_menu_item_new_with_mnemonic(_("_Record")); + image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_RECORD, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_items), image); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); + g_signal_connect (G_OBJECT (menu_items), "activate", + G_CALLBACK (call_record), + NULL); + gtk_widget_show (menu_items); + } - if(hold) - { - menu_items = gtk_check_menu_item_new_with_mnemonic (_("On _Hold")); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_items), - (selectedCall->_state == CALL_STATE_HOLD ? TRUE : FALSE)); - g_signal_connect(G_OBJECT (menu_items), "activate", - G_CALLBACK (call_hold), - NULL); - gtk_widget_show (menu_items); } - - if(record) + else { - menu_items = gtk_image_menu_item_new_with_mnemonic(_("_Record")); - image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_RECORD, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_items), image); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); - g_signal_connect (G_OBJECT (menu_items), "activate", - G_CALLBACK (call_record), - NULL); - gtk_widget_show (menu_items); + DEBUG("BUILD CONFERENCE MENU"); + + if(hangup_conf) + { + menu_items = gtk_image_menu_item_new_with_mnemonic(_("_Hang up")); + image = gtk_image_new_from_file( ICONS_DIR "/icon_hangup.svg"); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_items), image); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); + g_signal_connect (G_OBJECT (menu_items), "activate", + G_CALLBACK (conference_hang_up), + NULL); + gtk_widget_show (menu_items); + } + + if(hold_conf) + { + menu_items = gtk_check_menu_item_new_with_mnemonic (_("On _Hold")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_items), + (selectedCall->_state == CALL_STATE_HOLD ? TRUE : FALSE)); + g_signal_connect(G_OBJECT (menu_items), "activate", + G_CALLBACK (conference_hold), + NULL); + gtk_widget_show (menu_items); + } } if(accounts) { - add_registered_accounts_to_menu (menu); + add_registered_accounts_to_menu (menu); } - + if (event) { - button = event->button; - event_time = event->time; + button = event->button; + event_time = event->time; } else { - button = 0; - event_time = gtk_get_current_event_time (); + button = 0; + event_time = gtk_get_current_event_time (); } gtk_menu_attach_to_widget (GTK_MENU (menu), my_widget, NULL); @@ -1037,7 +1146,7 @@ static void ok_cb (GtkWidget *widget UNUSED, gpointer userdata) { // Update the internal data structure and the GUI calllist_add(current_calls, modified_call); - calltree_add_call(current_calls, modified_call); + calltree_add_call(current_calls, modified_call, NULL); sflphone_place_call(modified_call); calltree_display (current_calls); diff --git a/sflphone-client-gnome/src/toolbar.c b/sflphone-client-gnome/src/toolbar.c index 428e829c492b57017f527951fd3e55f67bde7a69..e320920458af6ba10779ec2902d7f5a0502fb0b9 100644 --- a/sflphone-client-gnome/src/toolbar.c +++ b/sflphone-client-gnome/src/toolbar.c @@ -52,7 +52,7 @@ call_mailbox( GtkWidget* widget UNUSED, gpointer data UNUSED) create_new_call (CALL, CALL_STATE_DIALING, "", account_id, _("Voicemail"), to, &mailbox_call); DEBUG("TO : %s" , mailbox_call->_peer_number); calllist_add( current_calls , mailbox_call ); - calltree_add_call( current_calls , mailbox_call ); + calltree_add_call( current_calls, mailbox_call, NULL); update_menus(); sflphone_place_call( mailbox_call ); calltree_display(current_calls); @@ -79,7 +79,7 @@ call_button( GtkWidget *widget UNUSED, gpointer data UNUSED) create_new_call (CALL, CALL_STATE_DIALING, "", "", "", selectedCall->_peer_number, &new_call); calllist_add(current_calls, new_call); - calltree_add_call(current_calls, new_call); + calltree_add_call(current_calls, new_call, NULL); sflphone_place_call(new_call); calltree_display (current_calls); } @@ -267,7 +267,6 @@ GtkWidget *create_toolbar () G_CALLBACK (rec_button), NULL); gtk_toolbar_insert(GTK_TOOLBAR(ret), GTK_TOOL_ITEM(recButton), -1); - return ret; } @@ -308,6 +307,7 @@ toolbar_update_buttons () gtk_signal_handler_unblock(transfertButton, transfertButtonConnId); callable_obj_t * selectedCall = calltab_get_selected_call(active_calltree); + conference_obj_t * selectedConf = calltab_get_selected_conf(active_calltree); if (selectedCall) { switch(selectedCall->_state) @@ -373,6 +373,26 @@ toolbar_update_buttons () break; } } + else if(selectedConf) + { + switch(selectedConf->_state) + { + case CONFERENCE_STATE_ACTIVE_ATACHED: + gtk_widget_set_sensitive( GTK_WIDGET(recButton), FALSE); + break; + case CONFERENCE_STATE_ACTIVE_DETACHED: + gtk_widget_set_sensitive( GTK_WIDGET(recButton), FALSE); + break; + case CONFERENCE_STATE_RECORD: + gtk_widget_set_sensitive( GTK_WIDGET(recButton), FALSE); + break; + case CONFERENCE_STATE_HOLD: + gtk_widget_set_sensitive( GTK_WIDGET(recButton), FALSE); + break; + default: + break; + } + } else { if( account_list_get_size() > 0 ) diff --git a/sflphone-client-gnome/src/toolbar.h b/sflphone-client-gnome/src/toolbar.h index 5af6e834e9de2cbac201408566cb3eaa0ecb0fcf..7c539f34fa95d480a6aeeff2f503a9d0bbd1f094 100644 --- a/sflphone-client-gnome/src/toolbar.h +++ b/sflphone-client-gnome/src/toolbar.h @@ -34,6 +34,7 @@ GtkToolItem * holdButton; GtkToolItem * transfertButton; GtkToolItem * unholdButton; GtkToolItem * mailboxButton; +GtkToolItem * detachButton; GtkToolItem * recButton; GtkToolItem * historyButton; GtkToolItem * contactButton; diff --git a/sflphone-client-gnome/tests/check_contacts.c b/sflphone-client-gnome/tests/check_contacts.c index 55625a5fc8f8a78fc8b5266098004d9f8f7dc64d..193cab4b8fb99bd4591487ea188a729523aa9563 100644 --- a/sflphone-client-gnome/tests/check_contacts.c +++ b/sflphone-client-gnome/tests/check_contacts.c @@ -37,23 +37,23 @@ END_TEST Suite * contacts_suite (void) { - Suite *s = suite_create ("Contacts"); + Suite *s = suite_create("Contacts"); - TCase *tc_cases = tcase_create ("EDS"); - tcase_add_test (tc_cases, test_eds); - suite_add_tcase (s, tc_cases); + TCase *tc_cases = tcase_create("EDS"); + tcase_add_test (tc_cases, test_eds); + suite_add_tcase (s, tc_cases); - return s; + return s; } int main (void) { - int number_failed; - Suite *s = contacts_suite (); - SRunner *sr = srunner_create (s); - srunner_run_all (sr, CK_NORMAL); - number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; + int number_failed; + Suite *s = contacts_suite (); + SRunner *sr = srunner_create (s); + srunner_run_all (sr, CK_NORMAL); + number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/sflphone-common/libs/pjproject/build.mak b/sflphone-common/libs/pjproject/build.mak index f3797ba67d9838efe7d22810639513c458686761..80ff11095e0fa962c6089f73eb1e8031f2fd8214 100644 --- a/sflphone-common/libs/pjproject/build.mak +++ b/sflphone-common/libs/pjproject/build.mak @@ -3,7 +3,7 @@ export MACHINE_NAME := auto export OS_NAME := auto export HOST_NAME := unix export CC_NAME := gcc -export TARGET_NAME := x86_64-unknown-linux-gnu +export TARGET_NAME := i686-pc-linux-gnu export CROSS_COMPILE := export LINUX_POLL := select @@ -42,7 +42,7 @@ endif # CFLAGS, LDFLAGS, and LIBS to be used by applications -export PJDIR := /home/emilou/git-repos/sflphone/sflphone-common/libs/pjproject +export PJDIR := /home/alexandresavard/Development/sflphone/sflphone-common/libs/pjproject export APP_CC := $(CROSS_COMPILE)$(CC_NAME) export APP_CFLAGS := -DPJ_AUTOCONF=1\ -O2\ diff --git a/sflphone-common/libs/pjproject/config.log b/sflphone-common/libs/pjproject/config.log index 22c00bbf045aea53ab3d41718071485913d6d703..656155f0ee52e06effbf9cbb591f01b20230ae85 100644 --- a/sflphone-common/libs/pjproject/config.log +++ b/sflphone-common/libs/pjproject/config.log @@ -10,11 +10,11 @@ generated by GNU Autoconf 2.61. Invocation command line was ## Platform. ## ## --------- ## -hostname = emilou-desktop -uname -m = x86_64 +hostname = alexandresavard-desktop +uname -m = i686 uname -r = 2.6.28-15-generic uname -s = Linux -uname -v = #49-Ubuntu SMP Tue Aug 18 19:25:34 UTC 2009 +uname -v = #52-Ubuntu SMP Wed Sep 9 10:49:34 UTC 2009 /usr/bin/uname -p = unknown /bin/uname -X = unknown @@ -27,7 +27,6 @@ uname -v = #49-Ubuntu SMP Tue Aug 18 19:25:34 UTC 2009 /usr/bin/oslevel = unknown /bin/universe = unknown -PATH: /home/emilou/bin PATH: /usr/local/sbin PATH: /usr/local/bin PATH: /usr/sbin @@ -35,7 +34,6 @@ PATH: /usr/bin PATH: /sbin PATH: /bin PATH: /usr/games -PATH: /usr/local/share/OpenSceneGraph/bin ## ----------- ## @@ -43,11 +41,11 @@ PATH: /usr/local/share/OpenSceneGraph/bin ## ----------- ## aconfigure:1802: checking build system type -aconfigure:1820: result: x86_64-unknown-linux-gnu +aconfigure:1820: result: i686-pc-linux-gnu aconfigure:1842: checking host system type -aconfigure:1857: result: x86_64-unknown-linux-gnu +aconfigure:1857: result: i686-pc-linux-gnu aconfigure:1879: checking target system type -aconfigure:1894: result: x86_64-unknown-linux-gnu +aconfigure:1894: result: i686-pc-linux-gnu aconfigure:1984: checking for gcc aconfigure:2000: found /usr/bin/gcc aconfigure:2011: result: gcc @@ -61,8 +59,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. aconfigure:2259: $? = 0 aconfigure:2266: gcc -v >&5 Using built-in specs. -Target: x86_64-linux-gnu -Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.3.3-5ubuntu4' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu +Target: i486-linux-gnu +Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.3.3-5ubuntu4' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu Thread model: posix gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4) aconfigure:2269: $? = 0 @@ -112,8 +110,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. aconfigure:2981: $? = 0 aconfigure:2988: g++ -v >&5 Using built-in specs. -Target: x86_64-linux-gnu -Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.3.3-5ubuntu4' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu +Target: i486-linux-gnu +Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.3.3-5ubuntu4' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu Thread model: posix gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4) aconfigure:2991: $? = 0 @@ -303,9 +301,9 @@ aconfigure:3848: $? = 0 aconfigure:3866: result: yes aconfigure:3877: checking for uuid_generate in -luuid aconfigure:3936: result: yes -aconfigure:3943: result: Setting PJ_M_NAME to x86_64 +aconfigure:3943: result: Setting PJ_M_NAME to i686 aconfigure:3950: checking memory alignment -aconfigure:3958: result: 8 bytes +aconfigure:3966: result: 4 bytes (default) aconfigure:3977: checking how to run the C preprocessor aconfigure:4017: gcc -E conftest.c aconfigure:4023: $? = 0 @@ -323,8 +321,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | /* end confdefs.h. */ | #include <ac_nonexistent.h> aconfigure:4093: result: gcc -E @@ -344,8 +342,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | /* end confdefs.h. */ | #include <ac_nonexistent.h> aconfigure:4203: checking for grep that handles long lines and -e @@ -417,8 +415,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -699,8 +697,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -793,8 +791,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -856,8 +854,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -950,8 +948,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -1013,8 +1011,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -1081,8 +1079,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -1175,8 +1173,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -1237,7 +1235,7 @@ aconfigure:9229: checking for net/if.h aconfigure:9253: gcc -c -O2 conftest.c >&5 aconfigure:9259: $? = 0 aconfigure:9274: result: yes -aconfigure:9285: result: Setting PJ_OS_NAME to x86_64-unknown-linux-gnu +aconfigure:9285: result: Setting PJ_OS_NAME to i686-pc-linux-gnu aconfigure:9292: result: Setting PJ_HAS_ERRNO_VAR to 1 aconfigure:9299: result: Setting PJ_HAS_HIGH_RES_TIMER to 1 aconfigure:9306: result: Setting PJ_HAS_MALLOC to 1 @@ -1275,8 +1273,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -1319,7 +1317,7 @@ aconfigure: failed program was: | #define PJ_HAS_TIME_H 1 | #define PJ_HAS_UNISTD_H 1 | #define PJ_HAS_NET_IF_H 1 -| #define PJ_OS_NAME "x86_64-unknown-linux-gnu" +| #define PJ_OS_NAME "i686-pc-linux-gnu" | #define PJ_HAS_ERRNO_VAR 1 | #define PJ_HAS_HIGH_RES_TIMER 1 | #define PJ_HAS_MALLOC 1 @@ -1372,8 +1370,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -1416,7 +1414,7 @@ aconfigure: failed program was: | #define PJ_HAS_TIME_H 1 | #define PJ_HAS_UNISTD_H 1 | #define PJ_HAS_NET_IF_H 1 -| #define PJ_OS_NAME "x86_64-unknown-linux-gnu" +| #define PJ_OS_NAME "i686-pc-linux-gnu" | #define PJ_HAS_ERRNO_VAR 1 | #define PJ_HAS_HIGH_RES_TIMER 1 | #define PJ_HAS_MALLOC 1 @@ -1455,8 +1453,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -1499,7 +1497,7 @@ aconfigure: failed program was: | #define PJ_HAS_TIME_H 1 | #define PJ_HAS_UNISTD_H 1 | #define PJ_HAS_NET_IF_H 1 -| #define PJ_OS_NAME "x86_64-unknown-linux-gnu" +| #define PJ_OS_NAME "i686-pc-linux-gnu" | #define PJ_HAS_ERRNO_VAR 1 | #define PJ_HAS_HIGH_RES_TIMER 1 | #define PJ_HAS_MALLOC 1 @@ -1560,8 +1558,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -1604,7 +1602,7 @@ aconfigure: failed program was: | #define PJ_HAS_TIME_H 1 | #define PJ_HAS_UNISTD_H 1 | #define PJ_HAS_NET_IF_H 1 -| #define PJ_OS_NAME "x86_64-unknown-linux-gnu" +| #define PJ_OS_NAME "i686-pc-linux-gnu" | #define PJ_HAS_ERRNO_VAR 1 | #define PJ_HAS_HIGH_RES_TIMER 1 | #define PJ_HAS_MALLOC 1 @@ -1668,8 +1666,8 @@ aconfigure: failed program was: | #define HAVE_LIBRT 1 | #define HAVE_LIBNSL 1 | #define HAVE_LIBUUID 1 -| #define PJ_M_NAME "x86_64" -| #define PJ_POOL_ALIGNMENT 8 +| #define PJ_M_NAME "i686" +| #define PJ_POOL_ALIGNMENT 4 | #define STDC_HEADERS 1 | #define HAVE_SYS_TYPES_H 1 | #define HAVE_SYS_STAT_H 1 @@ -1712,7 +1710,7 @@ aconfigure: failed program was: | #define PJ_HAS_TIME_H 1 | #define PJ_HAS_UNISTD_H 1 | #define PJ_HAS_NET_IF_H 1 -| #define PJ_OS_NAME "x86_64-unknown-linux-gnu" +| #define PJ_OS_NAME "i686-pc-linux-gnu" | #define PJ_HAS_ERRNO_VAR 1 | #define PJ_HAS_HIGH_RES_TIMER 1 | #define PJ_HAS_MALLOC 1 @@ -1797,7 +1795,7 @@ generated by GNU Autoconf 2.61. Invocation command line was CONFIG_COMMANDS = $ ./config.status -on emilou-desktop +on alexandresavard-desktop config.status:642: creating build.mak config.status:642: creating build/os-auto.mak @@ -1808,9 +1806,7 @@ config.status:642: creating pjsip/build/os-auto.mak config.status:642: creating third_party/build/portaudio/os-auto.mak config.status:642: creating third_party/build/os-auto.mak config.status:642: creating pjlib/include/pj/compat/os_auto.h -config.status:920: pjlib/include/pj/compat/os_auto.h is unchanged config.status:642: creating pjlib/include/pj/compat/m_auto.h -config.status:920: pjlib/include/pj/compat/m_auto.h is unchanged config.status:642: creating pjmedia/include/pjmedia/config_auto.h config.status:920: pjmedia/include/pjmedia/config_auto.h is unchanged config.status:642: creating pjmedia/include/pjmedia-codec/config_auto.h @@ -1832,7 +1828,7 @@ The next step now is to run 'make dep' and 'make'. ## Cache variables. ## ## ---------------- ## -ac_cv_build=x86_64-unknown-linux-gnu +ac_cv_build=i686-pc-linux-gnu ac_cv_c_bigendian=no ac_cv_c_compiler_gnu=yes ac_cv_cxx_compiler_gnu=yes @@ -1904,7 +1900,7 @@ ac_cv_header_uuid_uuid_h=yes ac_cv_header_winsock2_h=no ac_cv_header_winsock_h=no ac_cv_header_ws2tcpip_h=no -ac_cv_host=x86_64-unknown-linux-gnu +ac_cv_host=i686-pc-linux-gnu ac_cv_lib_crypto_ERR_load_BIO_strings=yes ac_cv_lib_m_fmod=yes ac_cv_lib_nsl_puts=yes @@ -1926,7 +1922,7 @@ ac_cv_prog_ac_ct_CXX=g++ ac_cv_prog_cc_c89= ac_cv_prog_cc_g=yes ac_cv_prog_cxx_g=yes -ac_cv_target=x86_64-unknown-linux-gnu +ac_cv_target=i686-pc-linux-gnu ## ----------------- ## ## Output variables. ## @@ -1979,24 +1975,24 @@ ac_os_objs='ioqueue_select.o file_access_unistd.o file_io_ansi.o os_core_unix.o ac_pa_cflags=' -DHAVE_SYS_SOUNDCARD_H -DHAVE_LINUX_SOUNDCARD_H -DPA_LITTLE_ENDIAN' ac_pa_use_alsa='1' ac_pa_use_oss='1' -ac_pjdir='/home/emilou/git-repos/sflphone/sflphone-common/libs/pjproject' +ac_pjdir='/home/alexandresavard/Development/sflphone/sflphone-common/libs/pjproject' ac_pjmedia_snd='pa_unix' bindir='${exec_prefix}/bin' -build='x86_64-unknown-linux-gnu' +build='i686-pc-linux-gnu' build_alias='' -build_cpu='x86_64' +build_cpu='i686' build_os='linux-gnu' -build_vendor='unknown' +build_vendor='pc' datadir='${datarootdir}' datarootdir='${prefix}/share' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' dvidir='${docdir}' exec_prefix='${prefix}' -host='x86_64-unknown-linux-gnu' +host='i686-pc-linux-gnu' host_alias='' -host_cpu='x86_64' +host_cpu='i686' host_os='linux-gnu' -host_vendor='unknown' +host_vendor='pc' htmldir='${docdir}' includedir='${prefix}/include' infodir='${datarootdir}/info' @@ -2016,11 +2012,11 @@ psdir='${docdir}' sbindir='${exec_prefix}/sbin' sharedstatedir='${prefix}/com' sysconfdir='${prefix}/etc' -target='x86_64-unknown-linux-gnu' +target='i686-pc-linux-gnu' target_alias='' -target_cpu='x86_64' +target_cpu='i686' target_os='linux-gnu' -target_vendor='unknown' +target_vendor='pc' ## ----------- ## ## confdefs.h. ## @@ -2035,8 +2031,8 @@ target_vendor='unknown' #define HAVE_LIBRT 1 #define HAVE_LIBNSL 1 #define HAVE_LIBUUID 1 -#define PJ_M_NAME "x86_64" -#define PJ_POOL_ALIGNMENT 8 +#define PJ_M_NAME "i686" +#define PJ_POOL_ALIGNMENT 4 #define STDC_HEADERS 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_STAT_H 1 @@ -2079,7 +2075,7 @@ target_vendor='unknown' #define PJ_HAS_TIME_H 1 #define PJ_HAS_UNISTD_H 1 #define PJ_HAS_NET_IF_H 1 -#define PJ_OS_NAME "x86_64-unknown-linux-gnu" +#define PJ_OS_NAME "i686-pc-linux-gnu" #define PJ_HAS_ERRNO_VAR 1 #define PJ_HAS_HIGH_RES_TIMER 1 #define PJ_HAS_MALLOC 1 diff --git a/sflphone-common/libs/pjproject/config.status b/sflphone-common/libs/pjproject/config.status index d38dfde47d27e397640b3fd570fcec8ada978935..ef4e31bd2d421f0bf73109faa0cf7a588e85ca25 100755 --- a/sflphone-common/libs/pjproject/config.status +++ b/sflphone-common/libs/pjproject/config.status @@ -337,7 +337,7 @@ Copyright (C) 2006 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." -ac_pwd='/home/emilou/git-repos/sflphone/sflphone-common/libs/pjproject' +ac_pwd='/home/alexandresavard/Development/sflphone/sflphone-common/libs/pjproject' srcdir='.' # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. @@ -530,17 +530,17 @@ s,@LIBS@,|#_!!_#|-lm -luuid -lnsl -lrt -lpthread -lasound -lssl -lcrypto,g s,@build_alias@,|#_!!_#|,g s,@host_alias@,|#_!!_#|,g s,@target_alias@,|#_!!_#|,g -s,@build@,|#_!!_#|x86_64-unknown-linux-gnu,g -s,@build_cpu@,|#_!!_#|x86_64,g -s,@build_vendor@,|#_!!_#|unknown,g +s,@build@,|#_!!_#|i686-pc-linux-gnu,g +s,@build_cpu@,|#_!!_#|i686,g +s,@build_vendor@,|#_!!_#|pc,g s,@build_os@,|#_!!_#|linux-gnu,g -s,@host@,|#_!!_#|x86_64-unknown-linux-gnu,g -s,@host_cpu@,|#_!!_#|x86_64,g -s,@host_vendor@,|#_!!_#|unknown,g +s,@host@,|#_!!_#|i686-pc-linux-gnu,g +s,@host_cpu@,|#_!!_#|i686,g +s,@host_vendor@,|#_!!_#|pc,g s,@host_os@,|#_!!_#|linux-gnu,g -s,@target@,|#_!!_#|x86_64-unknown-linux-gnu,g -s,@target_cpu@,|#_!!_#|x86_64,g -s,@target_vendor@,|#_!!_#|unknown,g +s,@target@,|#_!!_#|i686-pc-linux-gnu,g +s,@target_cpu@,|#_!!_#|i686,g +s,@target_vendor@,|#_!!_#|pc,g s,@target_os@,|#_!!_#|linux-gnu,g s,@CC@,|#_!!_#|gcc,g s,@CFLAGS@,|#_!!_#|-O2,g @@ -552,7 +552,7 @@ s,@OBJEXT@,|#_!!_#|o,g s,@CXX@,|#_!!_#|g++,g s,@CXXFLAGS@,|#_!!_#|-O2 ,g s,@ac_ct_CXX@,|#_!!_#|g++,g -s,@ac_pjdir@,|#_!!_#|/home/emilou/git-repos/sflphone/sflphone-common/libs/pjproject,g +s,@ac_pjdir@,|#_!!_#|/home/alexandresavard/Development/sflphone/sflphone-common/libs/pjproject,g s,@ac_build_mak_vars@,|#_!!_#|,g s,@CPP@,|#_!!_#|gcc -E,g s,@GREP@,|#_!!_#|/bin/grep,g @@ -837,8 +837,8 @@ s,^\([ #]*\)[^ ]*\([ ]*HAVE_LIBPTHREAD\)[ (].*,\1define\2 1 , s,^\([ #]*\)[^ ]*\([ ]*HAVE_LIBRT\)[ (].*,\1define\2 1 , s,^\([ #]*\)[^ ]*\([ ]*HAVE_LIBNSL\)[ (].*,\1define\2 1 , s,^\([ #]*\)[^ ]*\([ ]*HAVE_LIBUUID\)[ (].*,\1define\2 1 , -s,^\([ #]*\)[^ ]*\([ ]*PJ_M_NAME\)[ (].*,\1define\2 "x86_64" , -s,^\([ #]*\)[^ ]*\([ ]*PJ_POOL_ALIGNMENT\)[ (].*,\1define\2 8 , +s,^\([ #]*\)[^ ]*\([ ]*PJ_M_NAME\)[ (].*,\1define\2 "i686" , +s,^\([ #]*\)[^ ]*\([ ]*PJ_POOL_ALIGNMENT\)[ (].*,\1define\2 4 , s,^\([ #]*\)[^ ]*\([ ]*STDC_HEADERS\)[ (].*,\1define\2 1 , s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_TYPES_H\)[ (].*,\1define\2 1 , s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_STAT_H\)[ (].*,\1define\2 1 , @@ -889,7 +889,7 @@ s,^\([ #]*\)[^ ]*\([ ]*PJ_HAS_SYS_TYPES_H\)[ (].*,\1define\2 1 , s,^\([ #]*\)[^ ]*\([ ]*PJ_HAS_TIME_H\)[ (].*,\1define\2 1 , s,^\([ #]*\)[^ ]*\([ ]*PJ_HAS_UNISTD_H\)[ (].*,\1define\2 1 , s,^\([ #]*\)[^ ]*\([ ]*PJ_HAS_NET_IF_H\)[ (].*,\1define\2 1 , -s,^\([ #]*\)[^ ]*\([ ]*PJ_OS_NAME\)[ (].*,\1define\2 "x86_64-unknown-linux-gnu" , +s,^\([ #]*\)[^ ]*\([ ]*PJ_OS_NAME\)[ (].*,\1define\2 "i686-pc-linux-gnu" , s,^\([ #]*\)[^ ]*\([ ]*PJ_HAS_ERRNO_VAR\)[ (].*,\1define\2 1 , s,^\([ #]*\)[^ ]*\([ ]*PJ_HAS_HIGH_RES_TIMER\)[ (].*,\1define\2 1 , s,^\([ #]*\)[^ ]*\([ ]*PJ_HAS_MALLOC\)[ (].*,\1define\2 1 , diff --git a/sflphone-common/libs/pjproject/pjlib/include/pj/compat/m_auto.h b/sflphone-common/libs/pjproject/pjlib/include/pj/compat/m_auto.h index 4a068ac65a955e829f481233706fe11e14eb6a8f..4d4dce96418ea4b80512a1d4a3be7101373d0e78 100644 --- a/sflphone-common/libs/pjproject/pjlib/include/pj/compat/m_auto.h +++ b/sflphone-common/libs/pjproject/pjlib/include/pj/compat/m_auto.h @@ -27,7 +27,7 @@ */ /* Machine name, filled in by autoconf script */ -#define PJ_M_NAME "x86_64" +#define PJ_M_NAME "i686" /* Endianness. It's reported on pjsip list on 09/02/13 that autoconf * endianness detection failed for universal build, so special case diff --git a/sflphone-common/libs/pjproject/pjlib/include/pj/compat/os_auto.h b/sflphone-common/libs/pjproject/pjlib/include/pj/compat/os_auto.h index 7186ad9b458747c04a989f1c38c83d8bc43de7a3..cf51c14d8e224b3958dfbea9f8d58ba754a43770 100644 --- a/sflphone-common/libs/pjproject/pjlib/include/pj/compat/os_auto.h +++ b/sflphone-common/libs/pjproject/pjlib/include/pj/compat/os_auto.h @@ -28,7 +28,7 @@ */ /* Canonical OS name */ -#define PJ_OS_NAME "x86_64-unknown-linux-gnu" +#define PJ_OS_NAME "i686-pc-linux-gnu" /* Legacy macros */ /* #undef PJ_WIN32 */ @@ -162,7 +162,7 @@ #define PJ_NATIVE_STRING_IS_UNICODE 0 /* Pool alignment in bytes */ -#define PJ_POOL_ALIGNMENT 8 +#define PJ_POOL_ALIGNMENT 4 /* The type of atomic variable value: */ #define PJ_ATOMIC_VALUE_TYPE long diff --git a/sflphone-common/src/Makefile.am b/sflphone-common/src/Makefile.am index 928aadb91ec79a73486d3d61e774f2258152fa29..b0fdb972aa33695c20810a087eb8faf4185824d6 100644 --- a/sflphone-common/src/Makefile.am +++ b/sflphone-common/src/Makefile.am @@ -7,6 +7,7 @@ SUBDIRS = dbus audio config plug-in hooks history sip iax # Add here the cpp files to be build with sflphone sflphoned_SOURCES = \ + conference.cpp \ voiplink.cpp \ main.cpp \ managerimpl.cpp \ @@ -51,7 +52,8 @@ sflphoned_LDFLAGS= $(UUID_LIBS) noinst_LTLIBRARIES = libsflphone.la noinst_HEADERS = \ - voiplink.h \ + conference.h \ + voiplink.h \ managerimpl.h \ manager.h \ global.h \ diff --git a/sflphone-common/src/audio/Makefile.am b/sflphone-common/src/audio/Makefile.am index cf9e02da72100ebbd211a46fe83c53c5c827338a..cfbbf30f31c7eeb284814347fd5956bbd7862fbf 100644 --- a/sflphone-common/src/audio/Makefile.am +++ b/sflphone-common/src/audio/Makefile.am @@ -14,6 +14,8 @@ SUBDIRS = codecs audiortp sound alsa pulseaudio libaudio_la_SOURCES = \ audioloop.cpp \ ringbuffer.cpp \ + mainbuffer.cpp \ + recordable.cpp \ audiolayer.cpp \ audiodevice.cpp \ samplerateconverter.cpp \ @@ -25,5 +27,8 @@ noinst_HEADERS = \ ringbuffer.h \ audiolayer.h \ audiodevice.h \ + mainbuffer.h \ + recordable.h \ samplerateconverter.h + diff --git a/sflphone-common/src/audio/alsa/alsalayer.cpp b/sflphone-common/src/audio/alsa/alsalayer.cpp index 93f2aa2bf804b19759ab77232af65ec15181b8e7..16ebe977e065258e8ffa4a2b3d840535b4b4ac70 100644 --- a/sflphone-common/src/audio/alsa/alsalayer.cpp +++ b/sflphone-common/src/audio/alsa/alsalayer.cpp @@ -43,6 +43,8 @@ AlsaLayer::AlsaLayer (ManagerImpl* manager) _debug (" Constructor of AlsaLayer called\n"); /* Instanciate the audio thread */ _audioThread = new AudioThread (this); + + _urgentRingBuffer.createReadPointer(); } // Destructor @@ -128,6 +130,10 @@ AlsaLayer::startStream (void) startCaptureStream (); startPlaybackStream (); + _urgentRingBuffer.flush(); + _mainBuffer.flush(); + _mainBuffer.flushDefault(); + } void @@ -146,6 +152,8 @@ AlsaLayer::stopStream (void) int AlsaLayer::canGetMic() { + + /* int avail; if (!_CaptureHandle) @@ -159,12 +167,13 @@ AlsaLayer::canGetMic() } else return ( (avail<0) ?0:avail); - /* if(_CaptureHandle) return _micRingBuffer.AvailForGet(); else return 0;*/ + + return 0; } int @@ -175,7 +184,7 @@ AlsaLayer::getMic (void *buffer, int toCopy) return _micRingBuffer.Get(buffer, toCopy,100); } else - return 0;*/ + return 0; int res = 0; if (_CaptureHandle) { @@ -183,7 +192,9 @@ AlsaLayer::getMic (void *buffer, int toCopy) adjustVolume (buffer, toCopy, SFL_PCM_CAPTURE); } - return res; + return res;*/ + + return 0; } bool AlsaLayer::isCaptureActive (void) @@ -716,43 +727,55 @@ void AlsaLayer::audioCallback (void) // AvailForGet tell the number of chars inside the buffer // framePerBuffer are the number of data for one channel (left) urgentAvail = _urgentRingBuffer.AvailForGet(); - if (urgentAvail > 0) { + // Urgent data (dtmf, incoming call signal) come first. toGet = (urgentAvail < (int) (framesPerBufferAlsa * sizeof (SFLDataFormat))) ? urgentAvail : framesPerBufferAlsa * sizeof (SFLDataFormat); out = (SFLDataFormat*) malloc (toGet * sizeof (SFLDataFormat)); _urgentRingBuffer.Get (out, toGet, spkrVolume); /* Play the sound */ - write (out , toGet); + write (out, toGet); free (out); out=0; // Consume the regular one as well (same amount of bytes) - _voiceRingBuffer.Discard (toGet); + _mainBuffer.discard (toGet); + } else { + tone = _manager->getTelephoneTone(); toGet = 940 ; maxBytes = toGet * sizeof (SFLDataFormat) ; if (tone != 0) { + out = (SFLDataFormat*) malloc (maxBytes * sizeof (SFLDataFormat)); tone->getNext (out, toGet, spkrVolume); write (out , maxBytes); + } else if ( (tone=_manager->getTelephoneFile()) != 0) { + out = (SFLDataFormat*) malloc (maxBytes * sizeof (SFLDataFormat)); tone->getNext (out, toGet, spkrVolume); write (out , maxBytes); + } else { + // If nothing urgent, play the regular sound samples - normalAvail = _voiceRingBuffer.AvailForGet(); + normalAvail = _mainBuffer.availForGet(); toGet = (normalAvail < (int) (framesPerBufferAlsa * sizeof (SFLDataFormat))) ? normalAvail : framesPerBufferAlsa * sizeof (SFLDataFormat); out = (SFLDataFormat*) malloc (framesPerBufferAlsa * sizeof (SFLDataFormat)); if (toGet) { - _voiceRingBuffer.Get (out, toGet, spkrVolume); + + _mainBuffer.getData(out, toGet, spkrVolume); write (out, toGet); + } else { + bzero (out, framesPerBufferAlsa * sizeof (SFLDataFormat)); } + + _urgentRingBuffer.Discard (toGet); } free (out); @@ -761,19 +784,30 @@ void AlsaLayer::audioCallback (void) } // Additionally handle the mic's audio stream - //if(is_capture_running()){ - /*micAvailAlsa = snd_pcm_avail_update(_CaptureHandle); - if(micAvailAlsa > 0) { - micAvailPut = _micRingBuffer.AvailForPut(); - toPut = (micAvailAlsa <= micAvailPut) ? micAvailAlsa : micAvailPut; - in = (SFLDataFormat*)malloc(toPut * sizeof(SFLDataFormat)); - toPut = read (in, toPut); - if (in != 0) - { - _micRingBuffer.Put(in, toPut, 100); + int micAvailAlsa; + int micAvailPut; + int toPut; + SFLDataFormat* in; + + + // snd_pcm_sframes_t micAvailAlsa; + in = 0; + if(is_capture_running()) + { + micAvailAlsa = snd_pcm_avail_update(_CaptureHandle); + if(micAvailAlsa > 0) + { + micAvailPut = _mainBuffer.availForPut(); + toPut = (micAvailAlsa <= micAvailPut) ? micAvailAlsa : micAvailPut; + in = (SFLDataFormat*)malloc(toPut * sizeof(SFLDataFormat)); + toPut = read (in, toPut* sizeof(SFLDataFormat)); + if (in != 0) + { + _mainBuffer.putData(in, toPut, 100); + } + free(in); in=0; } - free(in); in=0; - }*/ + } } void* AlsaLayer::adjustVolume (void* buffer , int len, int stream) diff --git a/sflphone-common/src/audio/audiolayer.cpp b/sflphone-common/src/audio/audiolayer.cpp index 68eca5a9c7bc2045732f1588ceac705ca107c339..9f1119ff694baf871e77d9fa9c17b4b13818a667 100644 --- a/sflphone-common/src/audio/audiolayer.cpp +++ b/sflphone-common/src/audio/audiolayer.cpp @@ -22,7 +22,9 @@ void AudioLayer::flushMain (void) { ost::MutexLock guard (_mutex); - _voiceRingBuffer.flush(); + + // should pass call id + _mainBuffer.flush(); } void AudioLayer::flushUrgent (void) @@ -34,7 +36,7 @@ void AudioLayer::flushUrgent (void) void AudioLayer::flushMic (void) { ost::MutexLock guard (_mutex); - _micRingBuffer.flush(); + _mainBuffer.flushDefault(); } int AudioLayer::putUrgent (void* buffer, int toCopy) @@ -53,18 +55,18 @@ int AudioLayer::putUrgent (void* buffer, int toCopy) return 0; } -int AudioLayer::putMain (void *buffer, int toCopy) +int AudioLayer::putMain (void *buffer, int toCopy, CallID call_id) { int a; ost::MutexLock guard (_mutex); - a = _voiceRingBuffer.AvailForPut(); + a = _mainBuffer.availForPut(call_id); if (a >= toCopy) { - return _voiceRingBuffer.Put (buffer, toCopy, _defaultVolume); + return _mainBuffer.putData (buffer, toCopy, _defaultVolume, call_id); } else { _debug ("Chopping sound, Ouch! RingBuffer full ?\n"); - return _voiceRingBuffer.Put (buffer, a, _defaultVolume); + return _mainBuffer.putData (buffer, a, _defaultVolume, call_id); } return 0; diff --git a/sflphone-common/src/audio/audiolayer.h b/sflphone-common/src/audio/audiolayer.h index 9f17d75bcd75de65cac71d9190459cdce2b7c83e..816306221e0909d1c2dacee9e7dc7bdad16d0c02 100644 --- a/sflphone-common/src/audio/audiolayer.h +++ b/sflphone-common/src/audio/audiolayer.h @@ -25,11 +25,10 @@ #include "global.h" #include "audiodevice.h" #include "ringbuffer.h" - +#include "mainbuffer.h" #include <cc++/thread.h> // for ost::Mutex - #define FRAME_PER_BUFFER 160 /** @@ -37,8 +36,11 @@ * @brief Main sound class. Manages the data transfers between the application and the hardware. */ + +class Recordable; class ManagerImpl; + class AudioLayer { private: @@ -58,9 +60,7 @@ class AudioLayer { : _defaultVolume(100) , _layerType( type ) , _manager(manager) - , _voiceRingBuffer( SIZEBUF ) - , _urgentRingBuffer( SIZEBUF) - , _micRingBuffer( SIZEBUF ) + , _urgentRingBuffer( SIZEBUF, default_id ) , _indexIn ( 0 ) , _indexOut ( 0 ) , _sampleRate ( 0 ) @@ -138,7 +138,7 @@ class AudioLayer { * @param toCopy The size of the buffer * @return int The number of bytes copied */ - int putMain(void* buffer, int toCopy); + int putMain(void* buffer, int toCopy, CallID call_id = default_id); void flushMain (void); @@ -193,13 +193,40 @@ class AudioLayer { */ unsigned int getFrameSize() { return _frameSize; } + /** + * Get the layer type for this instance (either Alsa or PulseAudio) + * @return unsigned int The layer type + * + */ int getLayerType( void ) { return _layerType; } + /** + * Get a pointer to the application MainBuffer class. + * + * In order to send signal to other parts of the application, one must pass through the mainbuffer. + * Audio instances must be registered into the MainBuffer and bound together via the ManagerImpl. + * + * @return MainBuffer* a pointer to the MainBuffer instance + */ + MainBuffer* getMainBuffer( void ) { return &_mainBuffer; } + /** * Default volume for incoming RTP and Urgent sounds. */ unsigned short _defaultVolume; // 100 + + /** + * Set the audio recorder + */ + void setRecorderInstance(Recordable* rec) {_recorder = NULL; _recorder = rec;} + + /** + * Get the audio recorder + */ + Recordable* getRecorderInstance(Recordable* rec) {return _recorder;} + + protected: int _layerType; @@ -220,9 +247,21 @@ class AudioLayer { /** * Urgent ring buffer used for ringtones */ - RingBuffer _voiceRingBuffer; RingBuffer _urgentRingBuffer; - RingBuffer _micRingBuffer; + + /** + * Instance of the MainBuffer for the whole application + * + * In order to send signal to other parts of the application, one must pass through the mainbuffer. + * Audio instances must be registered into the MainBuffer and bound together via the ManagerImpl. + * + */ + MainBuffer _mainBuffer; + + /** + * A pointer to the recordable instance (may be a call or a conference) + */ + Recordable* _recorder; /** * Number of audio cards on which capture stream has been opened diff --git a/sflphone-common/src/audio/audiortp.cpp b/sflphone-common/src/audio/audiortp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f6527f3498406e1eee0dfd6ac110e0a48ce2fb8 --- /dev/null +++ b/sflphone-common/src/audio/audiortp.cpp @@ -0,0 +1,681 @@ +/* + * Copyright (C) 2004-2008 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> + * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <cstdio> +#include <cstdlib> +#include <ccrtp/rtp.h> +#include <assert.h> +#include <cstring> +#include <math.h> +#include <dlfcn.h> +#include <iostream> +#include <sstream> + +#include "../global.h" +#include "../manager.h" +#include "codecDescriptor.h" +#include "audiortp.h" +#include "audiolayer.h" +#include "ringbuffer.h" +#include "../user_cfg.h" +#include "../sipcall.h" + + +int AudioRtpRTX::count_rtp = 0; + +//////////////////////////////////////////////////////////////////////////////// +// AudioRtp +//////////////////////////////////////////////////////////////////////////////// +AudioRtp::AudioRtp() :_RTXThread (0), _symmetric(), _rtpMutex() +{ + +} + +AudioRtp::~AudioRtp (void) +{ + ost::MutexLock m (_rtpMutex); + + if (_RTXThread != _RTXThread) + { + delete _RTXThread; + _RTXThread = 0; + } + +} + +void +AudioRtp::createNewSession (SIPCall *ca) +{ + + ost::MutexLock m (_rtpMutex); + + _debug ("AudioRtp::Create new rtp session\n"); + + // something should stop the thread before... + + if (_RTXThread != 0) { + _debug ("**********************************************************\n"); + _debug ("! ARTP Failure: Thread already exists..., stopping it\n"); + _debug ("**********************************************************\n"); + delete _RTXThread; + _RTXThread = 0; + } + + // Start RTP Send/Receive threads + _symmetric = Manager::instance().getConfigInt (SIGNALISATION,SYMMETRIC) ? true : false; + + _RTXThread = new AudioRtpRTX (ca, _symmetric); + +} + +int +AudioRtp::start (void) +{ + ost::MutexLock m (_rtpMutex); + + if (_RTXThread == 0) { + _debug ("! ARTP Failure: Cannot start audiortp thread since not yet created\n"); + throw AudioRtpException(); + } + + + try { + if (_RTXThread->start() != 0) { + _debug ("! ARTP Failure: unable to start RTX Thread\n"); + return -1; + } + } catch (...) { + _debugException ("! ARTP Failure: when trying to start a thread"); + throw; + } + + return 0; +} + + +bool +AudioRtp::closeRtpSession () +{ + + ost::MutexLock m (_rtpMutex); + // This will make RTP threads finish. + _debug ("AudioRtp::Stopping rtp session\n"); + + try { + if (_RTXThread != 0) { + delete _RTXThread; + _RTXThread = 0; + } + } catch (...) { + _debugException ("! ARTP Exception: when stopping audiortp\n"); + throw; + } + + _debug ("AudioRtp::Audio rtp stopped\n"); + + return true; +} + +/* +void +AudioRtp::setRecording() +{ + + _debug ("AudioRtp::setRecording\n"); + _RTXThread->_ca->setRecording(); + +} +*/ + +//////////////////////////////////////////////////////////////////////////////// +// AudioRtpRTX Class // +//////////////////////////////////////////////////////////////////////////////// +AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, bool sym) : time (new ost::Time()), _ca (sipcall), _sessionSend (NULL), _sessionRecv (NULL), _session (NULL), + _sym (sym), micData (NULL), micDataConverted (NULL), micDataEncoded (NULL), spkrDataDecoded (NULL), spkrDataConverted (NULL), + converter (NULL), _layerSampleRate(),_codecSampleRate(), _layerFrameSize(), _audiocodec (NULL) +{ + + setCancel (cancelDefault); + // AudioRtpRTX should be close if we change sample rate + // TODO: Change bind address according to user settings. + // TODO: this should be the local ip not the external (router) IP + std::string localipConfig = _ca->getLocalIp(); // _ca->getLocalIp(); + ost::InetHostAddress local_ip (localipConfig.c_str()); + + _debug ("%i\n", _ca->getLocalAudioPort()); + _session = new ost::SymmetricRTPSession (local_ip, _ca->getLocalAudioPort()); + // _session = new ost::RTPSessionBase(local_ip, _ca->getLocalAudioPort()); + _sessionRecv = NULL; + _sessionSend = NULL; + + //mic, we receive from soundcard in stereo, and we send encoded + //encoding before sending + _audiolayer = Manager::instance().getAudioDriver(); + _layerFrameSize = _audiolayer->getFrameSize(); // in ms + _layerSampleRate = _audiolayer->getSampleRate(); + + // initBuffers(); + + // initAudioRtpSession(); + + _payloadIsSet = false; + _remoteIpIsSet = false; + + + count_rtp++; + // open files + std::string s_input; + std::string s_output; + + // convert count into string + std::stringstream out; + out << count_rtp; + + s_input = "/home/alexandresavard/Desktop/buffer_record/rtp_input_"; + s_input.append(out.str()); + + s_output = "/home/alexandresavard/Desktop/buffer_record/rtp_output_"; + s_output.append(out.str()); + + rtp_input_rec = new std::fstream(); + rtp_output_rec = new std::fstream(); + + rtp_input_rec->open(s_input.c_str(), std::fstream::out); + rtp_output_rec->open(s_output.c_str(), std::fstream::out); + +} + +AudioRtpRTX::~AudioRtpRTX () +{ + + ost::MutexLock m (_rtpRtxMutex); + + _debug ("Delete AudioRtpRTX instance in callid %s\n", _ca->getCallId().c_str()); + + try { + this->terminate(); + } catch (...) { + _debugException ("! ARTP: Thread destructor didn't terminate correctly"); + throw; + } + + _debug("Remove audio stream for call id %s\n", _ca->getCallId().c_str()); + _audiolayer->getMainBuffer()->unBindAll(_ca->getCallId()); + // Manager::instance().removeStream(_ca->getCallId()); + + _debug("DELETE print micData address %p\n", micData); + delete [] micData; + micData = NULL; + delete [] micDataConverted; + micDataConverted = NULL; + delete [] micDataEncoded; + micDataEncoded = NULL; + + delete [] spkrDataDecoded; + spkrDataDecoded = NULL; + delete [] spkrDataConverted; + spkrDataConverted = NULL; + + delete time; + time = NULL; + + delete converter; + converter = NULL; + + _ca = 0; + // _session->terminate(); + + delete _session; + _session = NULL; + + _debug ("AudioRtpRTX instance deleted\n"); + + rtp_input_rec->close(); + rtp_output_rec->close(); + +} + + +void +AudioRtpRTX::initBuffers() +{ + ost::MutexLock m (_rtpRtxMutex); + + _debug("AudioRtpRTX::initBuffers Init RTP buffers for %s\n", _ca->getCallId().c_str()); + + converter = new SamplerateConverter (_layerSampleRate , _layerFrameSize); + + nbSamplesMax = (int) (_layerSampleRate * _layerFrameSize /1000); + + + _debug("AudioRtpRTX::initBuffers NBSAMPLEMAX %i\n", nbSamplesMax); + + micData = new SFLDataFormat[nbSamplesMax]; + _debug("CREATE print micData address %p\n", micData); + micDataConverted = new SFLDataFormat[nbSamplesMax]; + micDataEncoded = new unsigned char[nbSamplesMax]; + + spkrDataConverted = new SFLDataFormat[nbSamplesMax]; + spkrDataDecoded = new SFLDataFormat[nbSamplesMax]; + + Manager::instance().addStream(_ca->getCallId()); + // _audiolayer->getMainBuffer()->bindCallID(_ca->getCallId()); +} + + +void +AudioRtpRTX::initAudioRtpSession (void) +{ + + try { + + _session->setSchedulingTimeout (100000); + _session->setExpireTimeout (1000000); + + + } catch (...) { + _debugException ("! ARTP Failure: initialisation failed"); + throw; + } + +} + +void +AudioRtpRTX::setRtpSessionMedia (void) +{ + + if (_ca == 0) { + _debug (" !ARTP: No call, can't init RTP media\n"); + return; + } + + AudioCodecType pl = (AudioCodecType)_ca->getLocalSDP()->get_session_media()->getPayload(); + _audiocodec = Manager::instance().getCodecDescriptorMap().instantiateCodec(pl); + + if (_audiocodec == NULL) { + _debug (" !ARTP: No audiocodec, can't init RTP media\n"); + return; + } + + _debug ("Init audio RTP session: codec payload %i\n", _audiocodec->getPayload()); + + // _audioCodecInstance = *_audiocodec; + + _codecSampleRate = _audiocodec->getClockRate(); + + _codecFrameSize = _audiocodec->getFrameSize(); + + if (_audiocodec->getPayload() == 9) { + _payloadIsSet = _session->setPayloadFormat (ost::DynamicPayloadFormat ( (ost::PayloadType) _audiocodec->getPayload(), _audiocodec->getClockRate())); + } else if (_audiocodec->hasDynamicPayload()) { + _payloadIsSet = _session->setPayloadFormat (ost::DynamicPayloadFormat ( (ost::PayloadType) _audiocodec->getPayload(), _audiocodec->getClockRate())); + } else if (!_audiocodec->hasDynamicPayload() && _audiocodec->getPayload() != 9) { + _payloadIsSet = _session->setPayloadFormat (ost::StaticPayloadFormat ( (ost::StaticPayloadType) _audiocodec->getPayload())); + } + + + +} + +void +AudioRtpRTX::setRtpSessionRemoteIp (void) +{ + + if (!_remoteIpIsSet) { + + _debug ("++++++++++++++++++++++++++ SET IP ADDRESS ++++++++++++++++++++++++++++\n"); + + if (_ca == 0) { + _debug (" !ARTP: No call, can't init RTP media \n"); + return; + } + + ost::InetHostAddress remote_ip (_ca->getLocalSDP()->get_remote_ip().c_str()); + + _debug ("Init audio RTP session: remote ip %s\n", _ca->getLocalSDP()->get_remote_ip().data()); + + if (!remote_ip) { + _debug (" !ARTP Thread Error: Target IP address [%s] is not correct!\n", _ca->getLocalSDP()->get_remote_ip().data()); + return; + } + + _debug ("++++Address: %s, audioport: %d\n", _ca->getLocalSDP()->get_remote_ip().c_str(), _ca->getLocalSDP()->get_remote_audio_port()); + + _debug ("++++Audioport: %d\n", (int) _ca->getLocalSDP()->get_remote_audio_port()); + + if (!_session->addDestination (remote_ip, (unsigned short) _ca->getLocalSDP()->get_remote_audio_port())) { + _debug (" !ARTP Thread Error: can't add destination to session!\n"); + return; + } + + _remoteIpIsSet = true; + } else { + _debug ("+++++++++++++++++++++++ IP ADDRESS ALREADY SET ++++++++++++++++++++++++\n"); + } + +} + + + +float +AudioRtpRTX::computeCodecFrameSize (int codecSamplePerFrame, int codecClockRate) +{ + return ( (float) codecSamplePerFrame * 1000.0) / (float) codecClockRate; +} + +int +AudioRtpRTX::computeNbByteAudioLayer (float codecFrameSize) +{ + return (int) ( (float) _layerSampleRate * codecFrameSize * (float) sizeof (SFLDataFormat) / 1000.0); +} + + +int +AudioRtpRTX::processDataEncode() +{ + + // compute codec framesize in ms + float fixed_codec_framesize = computeCodecFrameSize (_audiocodec->getFrameSize(), _audiocodec->getClockRate()); + + // compute nb of byte to get coresponding to 20 ms at audio layer frame size (44.1 khz) + int maxBytesToGet = computeNbByteAudioLayer (fixed_codec_framesize); + + // available bytes inside ringbuffer + int availBytesFromMic = _audiolayer->getMainBuffer()->availForGet(_ca->getCallId()); + + // _debug("AudioRtpRTX::processDataEncode() callid: %s availBytesFromMic %i\n", _ca->getCallId().c_str(), availBytesFromMic); + + // _debug("AudioRtpRTX::processDataEncode: availBytesFromMic: %i\n", availBytesFromMic); + // set available byte to maxByteToGet + int bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet; + // _debug("bytesAvail %i\n", bytesAvail); + if (bytesAvail == 0) + return 0; + + // _debug("AudioRtpRTX::processDataEncode: bytesAvail: %i\n", bytesAvail); + // Get bytes from micRingBuffer to data_from_mic + int nbSample = _audiolayer->getMainBuffer()->getData(micData , bytesAvail, 100, _ca->getCallId()) / sizeof (SFLDataFormat); + + rtp_output_rec->write((char*)micData, bytesAvail); + + // _debug("AudioRtpRTX::processDataEncode: nbSample: %i\n", nbSample); + + // nb bytes to be sent over RTP + int compSize = 0; + + // test if resampling is required + if (_audiocodec->getClockRate() != _layerSampleRate) { + + int nb_sample_up = nbSample; + //_debug("_nbSample audiolayer->getMic(): %i \n", nbSample); + + // Store the length of the mic buffer in samples for recording + _nSamplesMic = nbSample; + + nbSample = reSampleData (micData , micDataConverted, _audiocodec->getClockRate(), nb_sample_up, DOWN_SAMPLING); + + compSize = _audiocodec->codecEncode (micDataEncoded, micDataConverted, nbSample*sizeof (int16)); + + } else { + // no resampling required + compSize = _audiocodec->codecEncode (micDataEncoded, micData, nbSample*sizeof (int16)); + } + + return compSize; +} + + +void +AudioRtpRTX::processDataDecode (unsigned char* spkrData, unsigned int size, int& countTime) +{ + if (_audiocodec != NULL) { + + // Return the size of data in bytes + int expandedSize = _audiocodec->codecDecode (spkrDataDecoded , spkrData , size); + + // buffer _receiveDataDecoded ----> short int or int16, coded on 2 bytes + int nbSample = expandedSize / sizeof (SFLDataFormat); + + // test if resampling is required + + if (_audiocodec->getClockRate() != _layerSampleRate) { + + // Do sample rate conversion + int nb_sample_down = nbSample; + nbSample = reSampleData (spkrDataDecoded, spkrDataConverted, _codecSampleRate, nb_sample_down, UP_SAMPLING); + + rtp_input_rec->write((char*)spkrDataConverted, nbSample * sizeof (SFLDataFormat)); + + // Store the number of samples for recording + _nSamplesSpkr = nbSample; + + + + // put data in audio layer, size in byte + _audiolayer->getMainBuffer()->putData (spkrDataConverted, nbSample * sizeof (SFLDataFormat), 100, _ca->getCallId()); + + } else { + + // Stor the number of samples for recording + _nSamplesSpkr = nbSample; + + // put data in audio layer, size in byte + _audiolayer->getMainBuffer()->putData (spkrDataDecoded, nbSample * sizeof (SFLDataFormat), 100, _ca->getCallId()); + } + + // Notify (with a beep) an incoming call when there is already a call + countTime += time->getSecond(); + + if (Manager::instance().incomingCallWaiting() > 0) { + countTime = countTime % 500; // more often... + + if (countTime == 0) { + Manager::instance().notificationIncomingCall(); + } + } + + } else { + countTime += time->getSecond(); + } +} + +void +AudioRtpRTX::sendSessionFromMic (int timestamp) +{ + // STEP: + // 1. get data from mic + // 2. convert it to int16 - good sample, good rate + // 3. encode it + // 4. send it + + timestamp += time->getSecond(); + // no call, so we do nothing + + if (_ca==0) { + _debug (" !ARTP: No call associated (mic)\n"); + return; + } + + // AudioLayer* audiolayer = Manager::instance().getAudioDriver(); + if (!_audiolayer) { + _debug (" !ARTP: No audiolayer available for MIC\n"); + return; + } + + if (!_audiocodec) { + _debug (" !ARTP: No audiocodec available for MIC\n"); + return; + } + + + + int compSize = processDataEncode(); + + // putData put the data on RTP queue, sendImmediate bypass this queue + // _debug("AudioRtpRTX::sendSessionFromMic: timestamp: %i, compsize: %i\n", timestamp, compSize); + if((compSize != 0) && (micDataEncoded != NULL)) + _session->putData (timestamp, micDataEncoded, compSize); + // _session->sendImmediate(timestamp, micDataEncoded, compSize); + + +} + + +void +AudioRtpRTX::receiveSessionForSpkr (int& countTime) +{ + + if (_ca == 0) { + return; + } + + if (!_audiolayer) { + _debug (" !ARTP: No audiolayer available for SPEAKER\n"); + return; + } + + if (!_audiocodec) { + _debug (" !ARTP: No audiocodec available for SPEAKER\n"); + return; + } + + const ost::AppDataUnit* adu = NULL; + + // int is_waiting = _session->isWaiting(); + + // if (is_waiting != 0) + adu = _session->getData (_session->getFirstTimestamp()); + // else + // return; + + + + if (adu == NULL) + return; + + unsigned char* spkrData = (unsigned char*) adu->getData(); // data in char + + unsigned int size = adu->getSize(); // size in char + + processDataDecode (spkrData, size, countTime); + + if (adu != NULL) + { + delete adu; + adu = NULL; + } + +} + + +int +AudioRtpRTX::reSampleData (SFLDataFormat *input, SFLDataFormat *output, int sampleRate_codec, int nbSamples, int status) +{ + if (status==UP_SAMPLING) { + return converter->upsampleData (input, output, sampleRate_codec , _layerSampleRate , nbSamples); + } else if (status==DOWN_SAMPLING) { + return converter->downsampleData (micData , micDataConverted , sampleRate_codec , _layerSampleRate , nbSamples); + } else + + return 0; +} + + + +void +AudioRtpRTX::run () +{ + + int sessionWaiting; + + initBuffers(); + initAudioRtpSession(); + setRtpSessionRemoteIp(); + setRtpSessionMedia(); + + int timestep = _codecFrameSize; + + int countTime = 0; // for receive + + int threadSleep = 0; + + if (_codecSampleRate != 0) + threadSleep = (_codecFrameSize * 1000) / _codecSampleRate; + else + threadSleep = _layerFrameSize; + + TimerPort::setTimer (threadSleep); + + _audiolayer->startStream(); + + _audiolayer->getMainBuffer()->flush(_ca->getCallId()); + + _session->startRunning(); + + int timestamp = _session->getCurrentTimestamp(); // for mic + + _debug ("- ARTP Action: Start call %s\n",_ca->getCallId().c_str()); + + while (!testCancel()) { + + + // _debug("Main while loop for call: %s\n", _ca->getCallId().c_str()); + // Send session + sessionWaiting = _session->isWaiting(); + + sendSessionFromMic (timestamp); + timestamp += timestep; + // timestamp = _session->getCurrentTimestamp(); + + // Recv session + receiveSessionForSpkr (countTime); + + // Let's wait for the next transmit cycle + + + if (sessionWaiting == 1) { + // Record mic and speaker during conversation + _ca->recAudio.recData (spkrDataConverted,micData,_nSamplesSpkr,_nSamplesMic); + } else { + // Record mic only while leaving a message + _ca->recAudio.recData (micData,_nSamplesMic); + } + + + // Let's wait for the next transmit cycle + Thread::sleep (TimerPort::getTimer()); + + + // TimerPort::incTimer(20); // 'frameSize' ms + TimerPort::incTimer (threadSleep); + + } + + // _audiolayer->stopStream(); + _debug ("- ARTP Action: Stop call %s\n",_ca->getCallId().c_str()); + + +} + + +// EOF diff --git a/sflphone-common/src/audio/audiortp.h b/sflphone-common/src/audio/audiortp.h new file mode 100644 index 0000000000000000000000000000000000000000..f9dc1671a9297b15cd79bab4a537b456340a370d --- /dev/null +++ b/sflphone-common/src/audio/audiortp.h @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2004-2008 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __AUDIO_RTP_H__ +#define __AUDIO_RTP_H__ + +#include <cstdio> +#include <cstdlib> +#include <iostream> +#include <ccrtp/rtp.h> +#include <cc++/numbers.h> + +#include "../global.h" +// #include "plug-in/audiorecorder/audiorecord.h" +#include "../samplerateconverter.h" +#include "codecDescriptor.h" + +#include <fstream> + +#define UP_SAMPLING 0 +#define DOWN_SAMPLING 1 + + + +class AudioRtpException: public std::exception +{ + virtual const char* what() const throw() + { + return "AudioRtpException occured"; + } +}; + + +/** + * @file audiortp.h + * @brief Manage the real-time data transport in a SIP call + */ + + +class SIPCall; + +/////////////////////////////////////////////////////////////////////////////// +// Two pair of sockets +/////////////////////////////////////////////////////////////////////////////// +class AudioRtpRTX : public ost::Thread, public ost::TimerPort { + public: + /** + * Constructor + * @param sipcall The pointer on the SIP call + * @param sym Tells whether or not the voip links are symmetric + */ + AudioRtpRTX (SIPCall* sipcall, bool sym); + + /** + * Destructor + */ + ~AudioRtpRTX(); + + /** For incoming call notification */ + ost::Time *time; + + /** Thread associated method */ + virtual void run (); + + /** A SIP call */ + SIPCall* _ca; + + /** + * Update RTP session media info as received from SDP negociation + */ + void setRtpSessionMedia(void); + + /** + * Update RTP session remote ip destination as received from sip transaction + */ + void setRtpSessionRemoteIp(void); + + + friend class RtpTest; + + private: + + // copy constructor + AudioRtpRTX(const AudioRtpRTX& rh); + + // assignment operator + AudioRtpRTX& operator=(const AudioRtpRTX& rh); + + /** RTP session to send data */ + ost::RTPSession *_sessionSend; + + /** RTP session to receive data */ + ost::RTPSession *_sessionRecv; + + /** RTP symmetric session ( receive and send data in the same session ) */ + ost::SymmetricRTPSession *_session; + + /** Semaphore */ + // ost::Semaphore _start; + + /** Is the session symmetric or not */ + bool _sym; + + /** Mic-data related buffers */ + SFLDataFormat* micData; + SFLDataFormat* micDataConverted; + unsigned char* micDataEncoded; + + /** Speaker-data related buffers */ + SFLDataFormat* spkrDataDecoded; + SFLDataFormat* spkrDataConverted; + + /** Sample rate converter object */ + SamplerateConverter* converter; + + /** audio layer */ + AudioLayer *_audiolayer; + + /** Variables to process audio stream: sample rate for playing sound (typically 44100HZ) */ + int _layerSampleRate; + + /** Sample rate of the codec we use to encode and decode (most of time 8000HZ) */ + int _codecSampleRate; + + /** Length of the sound frame we capture in ms (typically 20ms) */ + int _layerFrameSize; + + /** Codecs frame size in samples (20 ms => 882 at 44.1kHz) + The exact value is stored in the codec */ + int _codecFrameSize; + + /** Speaker buffer length in samples once the data are resampled + * (used for mixing and recording) + */ + int _nSamplesSpkr; + + /** Mic buffer length in samples once the data are resampled + * (used for mixing and recording) + */ + int _nSamplesMic; + + /** + * Maximum number of sample for audio buffers (mic and spkr) + */ + int nbSamplesMax; + + + + bool _payloadIsSet; + bool _remoteIpIsSet; + + /** + * Init the RTP session. Create either symmetric or double sessions to manage data transport + * Set the payloads according to the manager preferences + */ + void initAudioRtpSession(void); + + /** + * Return the lenth the codec frame in ms + */ + float computeCodecFrameSize(int codecSamplePerFrame, int codecClockRate); + + /** + * Compute nb of byte to get coresponding to X ms at audio layer frame size (44.1 khz) + */ + int computeNbByteAudioLayer(float codecFrameSize); + + + int processDataEncode(); + + + void processDataDecode(unsigned char* spkrData, unsigned int size, int& countTime); + + + /** + * Get the data from the mic, encode it and send it through the RTP session + * @param timestamp To manage time and synchronizing + */ + void sendSessionFromMic(int timestamp); + + /** + * Get the data from the RTP packets, decode it and send it to the sound card + * @param countTime To manage time and synchronizing + */ + void receiveSessionForSpkr(int& countTime); + + /** + * Init the buffers used for processing sound data + */ + void initBuffers(void); + + /** + * Call the appropriate function, up or downsampling + * @param sampleRate_codec The sample rate of the codec selected to encode/decode the data + * @param nbSamples Number of samples to process + * @param status Type of resampling + * UPSAMPLING + * DOWNSAMPLING + * @return int The number of samples after process + */ + int reSampleData(SFLDataFormat *input, SFLDataFormat *output,int sampleRate_codec, int nbSamples, int status); + + /** The audio codec used during the session */ + AudioCodec *_audiocodec; + // AudioCodec _audioCodecInstance; + + /** Mutex */ + ost::Mutex _rtpRtxMutex; + + public: + + std::fstream *rtp_input_rec; + std::fstream *rtp_output_rec; + + static int count_rtp; + + +}; + +/////////////////////////////////////////////////////////////////////////////// +// Main class rtp +/////////////////////////////////////////////////////////////////////////////// +class AudioRtp { + public: + /** + * Constructor + */ + AudioRtp(); + + /** + * Destructor + */ + ~AudioRtp(); + + /** + * Create a brand new RTP session by calling the AudioRtpRTX constructor + * @param ca A pointer on a SIP call + */ + void createNewSession (SIPCall *ca); + + /** + * Start the AudioRtpRTX thread created with createNewSession + */ + int start(void); + + /** + * Close a RTP session and kills the remaining threads + */ + bool closeRtpSession( void ); + + /** + * Start recording + */ + // void setRecording (); + + friend class RtpTest; + + /** + * + */ + inline AudioRtpRTX * getAudioRtpRtxThread(void) { return _RTXThread; } + private: + // copy constructor + AudioRtp(const AudioRtp& rh); + + // assignment operator + AudioRtp& operator=(const AudioRtp& rh); + + /** The RTP thread */ + AudioRtpRTX* _RTXThread; + + /** Symmetric session or not */ + bool _symmetric; + + /** Mutex */ + ost::Mutex _rtpMutex; + +}; + +#endif // __AUDIO_RTP_H__ diff --git a/sflphone-common/src/audio/audiortp/AudioRtpSession.h b/sflphone-common/src/audio/audiortp/AudioRtpSession.h index 244ba129967196c4ca738dbf2d74a402b52c7015..6fb54b53ca91b66f03de2cee764f54ecef6a391b 100644 --- a/sflphone-common/src/audio/audiortp/AudioRtpSession.h +++ b/sflphone-common/src/audio/audiortp/AudioRtpSession.h @@ -199,6 +199,9 @@ namespace sfl { throw; } + _debug("Unbind audio RTP stream for call id %i\n", _ca->getCallId().c_str()); + _audiolayer->getMainBuffer()->unBindAll(_ca->getCallId()); + delete [] _micData; delete [] _micDataConverted; delete [] _micDataEncoded; @@ -219,6 +222,8 @@ namespace sfl { _micDataEncoded = new unsigned char[nbSamplesMax]; _spkrDataConverted = new SFLDataFormat[nbSamplesMax]; _spkrDataDecoded = new SFLDataFormat[nbSamplesMax]; + + _manager->addStream(_ca->getCallId()); } template <typename D> @@ -237,8 +242,10 @@ namespace sfl { void AudioRtpSession<D>::setSessionMedia(void) { assert(_ca); - - _audiocodec = _ca->getLocalSDP()->get_session_media (); + + AudioCodecType pl = (AudioCodecType)_ca->getLocalSDP()->get_session_media()->getPayload(); + _audiocodec = _manager->getCodecDescriptorMap().instantiateCodec(pl); + if (_audiocodec == NULL) { _debug ("No audiocodec, can't init RTP media\n"); throw AudioRtpSessionException(); @@ -299,7 +306,7 @@ namespace sfl { int maxBytesToGet = computeNbByteAudioLayer (fixed_codec_framesize); // available bytes inside ringbuffer - int availBytesFromMic = _audiolayer->canGetMic(); + int availBytesFromMic = _audiolayer->getMainBuffer()->availForGet(_ca->getCallId()); // set available byte to maxByteToGet int bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet; @@ -308,7 +315,7 @@ namespace sfl { return 0; // Get bytes from micRingBuffer to data_from_mic - int nbSample = _audiolayer->getMic (_micData , bytesAvail) / sizeof (SFLDataFormat); + int nbSample = _audiolayer->getMainBuffer()->getData(_micData , bytesAvail, 100, _ca->getCallId()) / sizeof (SFLDataFormat); // nb bytes to be sent over RTP int compSize = 0; @@ -347,14 +354,14 @@ namespace sfl { _nSamplesSpkr = nbSample; // put data in audio layer, size in byte - _audiolayer->putMain (_spkrDataConverted, nbSample * sizeof (SFLDataFormat)); + _audiolayer->getMainBuffer()->putData (_spkrDataConverted, nbSample * sizeof (SFLDataFormat), 100, _ca->getCallId()); } else { // Store the number of samples for recording _nSamplesSpkr = nbSample; // put data in audio layer, size in byte - _audiolayer->putMain (_spkrDataDecoded, nbSample * sizeof (SFLDataFormat)); + _audiolayer->getMainBuffer()->putData (_spkrDataConverted, nbSample * sizeof (SFLDataFormat), 100, _ca->getCallId()); } // Notify (with a beep) an incoming call when there is already a call diff --git a/sflphone-common/src/audio/codecs/Makefile.am b/sflphone-common/src/audio/codecs/Makefile.am index b294d3e779499f1594455be3795eaa817d101b08..230ee7bbc0dce19ecfd5f02f18236afefb84965d 100644 --- a/sflphone-common/src/audio/codecs/Makefile.am +++ b/sflphone-common/src/audio/codecs/Makefile.am @@ -110,7 +110,7 @@ uninstall-libcodec_speex_wb_so: rm -f $(sflcodecdir)/libcodec_speex_wb.so uninstall-libcodec_speex_ub_so: rm -f $(sflcodecdir)/libcodec_speex_ub.so +uninstall-libcodec_celt_so: + rm -f $(sflcodecdir)/libcodec_celt.so rm -rf $(sflcodecdir) -uninstall-libcodec_celt_so: libcodec_celt.so - $(INSTALL_PROGRAM) libcodec_celt.so $(sflcodecdir) diff --git a/sflphone-common/src/audio/codecs/codecDescriptor.cpp b/sflphone-common/src/audio/codecs/codecDescriptor.cpp index d0fa1da9274a5325ab164a90cfe3aa0f89ce691d..edf8586f2198f823faae914c32033d29d7b24e57 100644 --- a/sflphone-common/src/audio/codecs/codecDescriptor.cpp +++ b/sflphone-common/src/audio/codecs/codecDescriptor.cpp @@ -3,6 +3,7 @@ * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -125,7 +126,7 @@ CodecDescriptor::addCodec (AudioCodecType payload UNUSED) double CodecDescriptor::getBitRate (AudioCodecType payload) { - CodecsMap::iterator iter = _CodecsMap.find (payload); + CodecsMap::iterator iter = _CodecsMap.find(payload); if (iter!=_CodecsMap.end()) return (iter->second->getBitRate()); @@ -250,13 +251,14 @@ CodecDescriptor::loadCodec (std::string path) AudioCodec* a = createCodec(); - p = CodecHandlePointer (a, codecHandle); + p = CodecHandlePointer(a, codecHandle); - _CodecInMemory.push_back (p); + _CodecInMemory.push_back(p); return a; } + void CodecDescriptor::unloadCodec (CodecHandlePointer p) { @@ -272,6 +274,34 @@ CodecDescriptor::unloadCodec (CodecHandlePointer p) dlclose (p.second); } +AudioCodec* +CodecDescriptor::instantiateCodec(AudioCodecType payload) +{ + + using std::cerr; + + std::vector< CodecHandlePointer >::iterator iter = _CodecInMemory.begin(); + while(iter != _CodecInMemory.end()) + { + if (iter->first->getPayload() == payload) + { + create_t* createCodec = (create_t*) dlsym (iter->second , "create"); + + if (dlerror()) + cerr << dlerror() << '\n'; + + AudioCodec* a = createCodec(); + + return a; + + } + + iter++; + } + + return NULL; +} + AudioCodec* CodecDescriptor::getFirstCodecAvailable (void) { diff --git a/sflphone-common/src/audio/codecs/codecDescriptor.h b/sflphone-common/src/audio/codecs/codecDescriptor.h index 3462afbcd1f73e1eb7ec7d735aeebe0814b97cb9..9ca8773a4c8986c4ba015caafafb1963b0d0b98f 100644 --- a/sflphone-common/src/audio/codecs/codecDescriptor.h +++ b/sflphone-common/src/audio/codecs/codecDescriptor.h @@ -193,6 +193,12 @@ class CodecDescriptor { */ AudioCodec* getFirstCodecAvailable( void ); + /** + * Instantiate a codec, used in AudioRTP to get an instance of Codec per call + * @param CodecHandlePointer The map containing the pointer on the object and the pointer on the handle function + */ + AudioCodec* instantiateCodec(AudioCodecType payload); + private: /** diff --git a/sflphone-common/src/audio/codecs/g722.cpp b/sflphone-common/src/audio/codecs/g722.cpp index a95a0a865304dfcd0b72eb46579fe4219a04e118..5280fa1f337869b0a9e4ab49b74fe660d4bcd236 100644 --- a/sflphone-common/src/audio/codecs/g722.cpp +++ b/sflphone-common/src/audio/codecs/g722.cpp @@ -40,7 +40,7 @@ class G722 : public AudioCodec G722 (int payload=9) : AudioCodec (payload, "G722") { _clockRate = 16000; - _frameSize = 320; // samples, 10 ms at 16kHz + _frameSize = 320; // samples, 20 ms at 16kHz _channel = 1; _bitrate = 64; _bandwidth = 80; diff --git a/sflphone-common/src/audio/mainbuffer.cpp b/sflphone-common/src/audio/mainbuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb88bc5a6f2d41f220eb52708a35a72edcd0333d --- /dev/null +++ b/sflphone-common/src/audio/mainbuffer.cpp @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author : Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "mainbuffer.h" + +MainBuffer::MainBuffer() +{ + mixBuffer = new SFLDataFormat[STATIC_BUFSIZE]; +} + + +MainBuffer::~MainBuffer() +{ + + delete mixBuffer; + mixBuffer = NULL; +} + +CallIDSet* MainBuffer::getCallIDSet(CallID call_id) +{ + + // _debug("MainBuffer::getCallIDSet\n"); + + CallIDMap::iterator iter = _callIDMap.find(call_id); + if (iter == _callIDMap.end()) + { + // _debug("CallIDSet with ID: \"%s\" doesn't exist! \n", call_id.c_str()); + return NULL; + } + else + return iter->second; + +} + +bool MainBuffer::createCallIDSet(CallID set_id) +{ + _debug("---- MainBuffer::createCallIDSet %s\n", set_id.c_str()); + + CallIDSet* newCallIDSet = new CallIDSet; + + _callIDMap.insert(pair<CallID, CallIDSet*>(set_id, newCallIDSet)); + // _callIDMap[set_id] = new CallIDSet; + + return true; + +} + +bool MainBuffer::removeCallIDSet(CallID set_id) +{ + + _debug("---- MainBuffer::removeCallIDSet %s\n", set_id.c_str()); + + + CallIDSet* callid_set = getCallIDSet(set_id); + + if(callid_set != NULL) + { + if (_callIDMap.erase(set_id) != 0) + { + _debug(" callid set %s erased!\n", set_id.c_str()); + return true; + } + else + { + _debug(" error while removing callid set %s!\n", set_id.c_str()); + return false; + } + } + else + { + _debug(" callid set %s does not exist!\n", set_id.c_str()); + return false; + } + +} + +void MainBuffer::addCallIDtoSet(CallID set_id, CallID call_id) +{ + _debug("---- MainBuffer::addCallIDtoSet %s in %s\n", set_id.c_str(), call_id.c_str()); + + CallIDSet* callid_set = getCallIDSet(set_id); + callid_set->insert(call_id); + +} + +void MainBuffer::removeCallIDfromSet(CallID set_id, CallID call_id) +{ + _debug("---- MainBuffer::removeCallIDfromSet element %s from %s\n", call_id.c_str(), set_id.c_str()); + + CallIDSet* callid_set = getCallIDSet(set_id); + if(callid_set != NULL) + { + if( callid_set->erase(call_id) != 0) + { + _debug(" callid %s erased from set %s!\n", call_id.c_str(), set_id.c_str()); + } + else + { + _debug(" error while removing callid %s from set %s!\n", call_id.c_str(), set_id.c_str()); + } + } + else + { + _debug(" callid set %s does not exist!\n", set_id.c_str()); + } +} + + +RingBuffer* MainBuffer::getRingBuffer(CallID call_id) +{ + + RingBufferMap::iterator iter = _ringBufferMap.find(call_id); + if (iter == _ringBufferMap.end()) + { + // _debug("ringBuffer with ID: \"%s\" doesn't exist! \n", call_id.c_str()); + return NULL; + } + else + return iter->second; +} + + +RingBuffer* MainBuffer::createRingBuffer(CallID call_id) +{ + + _debug("---- MainBuffer::createRingBuffer callid %s\n", call_id.c_str()); + + RingBuffer* newRingBuffer = new RingBuffer(SIZEBUF, call_id); + + _ringBufferMap.insert(pair<CallID, RingBuffer*>(call_id, newRingBuffer)); + + return newRingBuffer; +} + + +bool MainBuffer::removeRingBuffer(CallID call_id) +{ + + _debug("---- MainBuffer::removeRingBuffer call_id %s\n", call_id.c_str()); + + RingBuffer* ring_buffer = getRingBuffer(call_id); + if(ring_buffer != NULL) + { + if (_ringBufferMap.erase(call_id) != 0) + { + _debug(" ringbuffer %s removed!\n", call_id.c_str()); + return true; + } + else + { + _debug(" error while deleting ringbuffer %s!\n", call_id.c_str()); + return false; + } + } + else + { + _debug(" error ringbuffer %s does not exist!\n", call_id.c_str()); + return true; + } +} + + +void MainBuffer::bindCallID(CallID call_id1, CallID call_id2) +{ + + ost::MutexLock guard (_mutex); + + _debug("---- MainBuffer::bindCallID %s and callid %s\n", call_id1.c_str(), call_id2.c_str()); + + RingBuffer* ring_buffer; + CallIDSet* callid_set; + + if((ring_buffer = getRingBuffer(call_id1)) == NULL) + createRingBuffer(call_id1); + + if((callid_set = getCallIDSet(call_id1)) == NULL) + createCallIDSet(call_id1); + + if((ring_buffer = getRingBuffer(call_id2)) == NULL) + createRingBuffer(call_id2); + + if((callid_set = getCallIDSet(call_id2)) == NULL) + createCallIDSet(call_id2); + + getRingBuffer(call_id1)->createReadPointer(call_id2); + getRingBuffer(call_id2)->createReadPointer(call_id1); + + addCallIDtoSet(call_id1, call_id2); + addCallIDtoSet(call_id2, call_id1); + +} + + +void MainBuffer::unBindCallID(CallID call_id1, CallID call_id2) +{ + + ost::MutexLock guard (_mutex); + + _debug("---- MainBuffer::unBindCallID %s and callid %s\n", call_id1.c_str(), call_id2.c_str()); + + removeCallIDfromSet(call_id1, call_id2); + removeCallIDfromSet(call_id2, call_id1); + + RingBuffer* ringbuffer; + + ringbuffer = getRingBuffer(call_id2); + if(ringbuffer != NULL) + { + + ringbuffer->removeReadPointer(call_id1); + + if(ringbuffer->getNbReadPointer() == 0) + { + removeCallIDSet(call_id2); + removeRingBuffer(call_id2); + } + + } + + ringbuffer = getRingBuffer(call_id1); + if(ringbuffer != NULL) + { + ringbuffer->removeReadPointer(call_id2); + + if(ringbuffer->getNbReadPointer() == 0) + { + removeCallIDSet(call_id1); + removeRingBuffer(call_id1); + } + } + + +} + +void MainBuffer::unBindAll(CallID call_id) +{ + + ost::MutexLock guard (_mutex); + + CallIDSet* callid_set = getCallIDSet(call_id); + + if (callid_set == NULL) + return; + + if (callid_set->empty()) + return; + + CallIDSet temp_set = *callid_set; + + CallIDSet::iterator iter_set = temp_set.begin(); + + _debug("MainBuffer::unBindAll\n"); + while (iter_set != temp_set.end()) + { + CallID call_id_in_set = *iter_set; + unBindCallID(call_id, call_id_in_set); + + iter_set++; + } + +} + + +int MainBuffer::putData(void *buffer, int toCopy, unsigned short volume, CallID call_id) +{ + + ost::MutexLock guard (_mutex); + + RingBuffer* ring_buffer = getRingBuffer(call_id); + + if (ring_buffer == NULL) + { + // _debug("Input RingBuffer ID: \"%s\" does not exist!\n", call_id.c_str()); + return 0; + } + + int a; + + // ost::MutexLock guard (_mutex); + a = ring_buffer->AvailForPut(); + + if (a >= toCopy) { + return ring_buffer->Put (buffer, toCopy, volume); + } else { + // _debug ("Chopping sound, Ouch! RingBuffer full ?\n"); + return ring_buffer->Put (buffer, a, volume); + } + + return 0; + +} + +int MainBuffer::availForPut(CallID call_id) +{ + + ost::MutexLock guard (_mutex); + + RingBuffer* ringbuffer = getRingBuffer(call_id); + + if (ringbuffer == NULL) + return 0; + else + return ringbuffer->AvailForPut(); + +} + + +int MainBuffer::getData(void *buffer, int toCopy, unsigned short volume, CallID call_id) +{ + ost::MutexLock guard (_mutex); + + // _debug("MainBuffer::getData by \"%s\", toCopy %i\n",call_id.c_str(), toCopy); + + CallIDSet* callid_set = getCallIDSet(call_id); + + int nbSmplToCopy = toCopy / sizeof(SFLDataFormat); + + if(callid_set == NULL) + return 0; + + if(callid_set->empty()) + { + // _debug("CallIDSet with ID: \"%s\" is empty!\n", call_id.c_str()); + return 0; + } + + if (callid_set->size() == 1) + { + // _debug("callid_set->size() == %i\n", callid_set->size()); + CallIDSet::iterator iter_id = callid_set->begin(); + + if (iter_id != callid_set->end()) + { + // _debug("MainBuffer::getData in buffer %s by %s \n", (*iter_id).c_str(), call_id.c_str()); + return getDataByID(buffer, toCopy, volume, *iter_id, call_id); + } + else + return 0; + } + else + { + + // _debug("callid_set->size() == %i\n", callid_set->size()); + + for (int k = 0; k < nbSmplToCopy; k++) + { + ((SFLDataFormat*)(buffer))[k] = 0; + } + + int size; + // _debug("CallIDSet with ID: \"%s\" is a conference!\n", call_id.c_str()); + CallIDSet::iterator iter_id; + for(iter_id = callid_set->begin(); iter_id != callid_set->end(); iter_id++) + { + // _debug("MainBuffer::getData in buffer %s by %s \n", (*iter_id).c_str(), call_id.c_str()); + + size = getDataByID(mixBuffer, toCopy, volume, (CallID)(*iter_id), call_id); + // _debug("MainBuffer::getData: tocopy %i, size: %i \n", toCopy, size); + + if (size > 0) + { + for (int k = 0; k < nbSmplToCopy; k++) + { + ((SFLDataFormat*)(buffer))[k] += mixBuffer[k]; + } + } + } + + // _debug("MainBuffer::getData data mixed successfully\n"); + + return size; + } +} + + +int MainBuffer::getDataByID(void *buffer, int toCopy, unsigned short volume, CallID call_id, CallID reader_id) +{ + + // _debug("MainBuffer::getDataByID in buffer %s by %s \n", call_id.c_str(), reader_id.c_str()); + + RingBuffer* ring_buffer = getRingBuffer(call_id); + + if (ring_buffer == NULL) + { + // _debug("Output RingBuffer ID: \"%s\" does not exist!\n", call_id.c_str()); + return 0; + } + + return ring_buffer->Get (buffer, toCopy, volume, reader_id); + + return 0; + +} + + +int MainBuffer::availForGet(CallID call_id) +{ + + ost::MutexLock guard (_mutex); + + CallIDSet* callid_set = getCallIDSet(call_id); + + if (callid_set == NULL) + return 0; + + if (callid_set->empty()) + { + _debug("CallIDSet with ID: \"%s\" is empty!\n", call_id.c_str()); + return 0; + } + + if (callid_set->size() == 1) + { + CallIDSet::iterator iter_id = callid_set->begin(); + // _debug("MainBuffer::availForGet availForGetByID(%s,%s)\n", (*iter_id).c_str(), call_id.c_str()); + if((call_id != default_id) && (*iter_id == call_id)) + { + _debug("**********************************************************************\n"); + _debug("Error an RTP session ring buffer is not supposed to have a readpointer on tiself\n"); + _debug("This problem should not occur since we have %i element\n", callid_set->size()); + } + // else + return availForGetByID(*iter_id, call_id); + } + else + { + // _debug("CallIDSet with ID: \"%s\" is a conference!\n", call_id.c_str()); + int avail_bytes = 99999; + int nb_bytes; + CallIDSet::iterator iter_id = callid_set->begin(); + for(iter_id = callid_set->begin(); iter_id != callid_set->end(); iter_id++) + { + nb_bytes = availForGetByID(*iter_id, call_id); + if (nb_bytes < avail_bytes) + avail_bytes = nb_bytes; + } + return avail_bytes; + } + +} + + +int MainBuffer::availForGetByID(CallID call_id, CallID reader_id) +{ + + if((call_id != default_id) && (reader_id == call_id)) + { + _debug("**********************************************************************\n"); + _debug("Error an RTP session ring buffer is not supposed to have a readpointer on tiself\n"); + } + + RingBuffer* ringbuffer = getRingBuffer(call_id); + + if (ringbuffer == NULL) + { + _debug("Error: ring buffer does not exist\n"); + return 0; + } + else + return ringbuffer->AvailForGet(reader_id); + +} + + +int MainBuffer::discard(int toDiscard, CallID call_id) +{ + // _debug("MainBuffer::discard\n"); + + ost::MutexLock guard (_mutex); + + CallIDSet* callid_set = getCallIDSet(call_id); + + if (callid_set == NULL) + return 0; + + if(callid_set->empty()) + { + // _debug("CallIDSet with ID: \"%s\" is empty!\n", call_id.c_str()); + return 0; + } + + + if (callid_set->size() == 1) + { + CallIDSet::iterator iter_id = callid_set->begin(); + // _debug("Discard Data in \"%s\" RingBuffer for \"%s\" ReaderPointer\n",(*iter_id).c_str(),call_id.c_str()); + return discardByID(toDiscard, *iter_id, call_id); + } + else + { + // _debug("CallIDSet with ID: \"%s\" is a conference!\n", call_id.c_str()); + CallIDSet::iterator iter_id; + for(iter_id = callid_set->begin(); iter_id != callid_set->end(); iter_id++) + { + discardByID(toDiscard, *iter_id, call_id); + } + return toDiscard; + } + +} + + +int MainBuffer::discardByID(int toDiscard, CallID call_id, CallID reader_id) +{ + + RingBuffer* ringbuffer = getRingBuffer(call_id); + + if(ringbuffer == NULL) + return 0; + else + return ringbuffer->Discard(toDiscard, reader_id); + +} + + + +void MainBuffer::flush(CallID call_id) +{ + ost::MutexLock guard (_mutex); + + // _debug("MainBuffer::flush\n"); + + CallIDSet* callid_set = getCallIDSet(call_id); + + if (callid_set == NULL) + return; + + if(callid_set->empty()) + { + // _debug("CallIDSet with ID: \"%s\" is empty!\n", call_id.c_str()); + } + + if (callid_set->size() == 1) + { + CallIDSet::iterator iter_id = callid_set->begin(); + flushByID(*iter_id, call_id); + } + else + { + // _debug("CallIDSet with ID: \"%s\" is a conference!\n", call_id.c_str()); + CallIDSet::iterator iter_id; + for(iter_id = callid_set->begin(); iter_id != callid_set->end(); iter_id++) + { + flushByID(*iter_id, call_id); + } + } + +} + +void MainBuffer::flushDefault() +{ + ost::MutexLock guard (_mutex); + + flushByID(default_id, default_id); + +} + + +void MainBuffer::flushByID(CallID call_id, CallID reader_id) +{ + + RingBuffer* ringbuffer = getRingBuffer(call_id); + + if(ringbuffer != NULL) + ringbuffer->flush(reader_id); +} diff --git a/sflphone-common/src/audio/mainbuffer.h b/sflphone-common/src/audio/mainbuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..ed122e207461183a114a59920c0281791e94f5d0 --- /dev/null +++ b/sflphone-common/src/audio/mainbuffer.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2004-2005 Savoir-Faire Linux inc. + * Author : Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MAIN_BUFFER__ +#define __MAIN_BUFFER__ + +#include <map> +#include <set> +#include <cc++/thread.h> // for ost::Mutex + +#include "../global.h" +#include "../call.h" +#include "ringbuffer.h" + + + +typedef std::map<CallID, RingBuffer*> RingBufferMap; + +typedef std::set<CallID> CallIDSet; + +typedef std::map<CallID, CallIDSet*> CallIDMap; + +class MainBuffer { + +public: + + MainBuffer(); + + ~MainBuffer(); + + CallIDSet* getCallIDSet(CallID call_id); + + bool createCallIDSet(CallID set_id); + + bool removeCallIDSet(CallID set_id); + + void addCallIDtoSet(CallID set_id, CallID call_id); + + void removeCallIDfromSet(CallID set_id, CallID call_id); + + RingBuffer* createRingBuffer(CallID call_id); + + bool removeRingBuffer(CallID call_id); + + void bindCallID(CallID call_id1, CallID call_id2 = default_id); + + void unBindCallID(CallID call_id1, CallID call_id2 = default_id); + + void unBindAll(CallID call_id); + + int putData(void *buffer, int toCopy, unsigned short volume = 100, CallID call_id = default_id); + + int getData(void *buffer, int toCopy, unsigned short volume = 100, CallID call_id = default_id); + + int availForPut(CallID call_id = default_id); + + int availForGet(CallID call_id = default_id); + + int discard(int toDiscard, CallID call_id = default_id); + + void flush(CallID call_id = default_id); + + void flushDefault(); + + private: + + RingBuffer* getRingBuffer(CallID call_id); + + int getDataByID(void *buffer, int toCopy, unsigned short volume, CallID call_id, CallID reader_id); + + int availForGetByID(CallID call_id, CallID reader_id); + + int discardByID(int toDiscard, CallID call_id, CallID reader_id); + + void flushByID(CallID call_id, CallID reader_id); + + RingBufferMap _ringBufferMap; + + CallIDMap _callIDMap; + + SFLDataFormat* mixBuffer; + + ost::Mutex _mutex; + + public: + + friend class MainBufferTest; +}; + +#endif diff --git a/sflphone-common/src/audio/pulseaudio/pulselayer.cpp b/sflphone-common/src/audio/pulseaudio/pulselayer.cpp index fb576f882c295c98a736deeec80e7761c1f1c95c..bc83dcc6261d7fe3e9eb306a15f93c6c13483ba9 100644 --- a/sflphone-common/src/audio/pulseaudio/pulselayer.cpp +++ b/sflphone-common/src/audio/pulseaudio/pulselayer.cpp @@ -40,6 +40,7 @@ PulseLayer::PulseLayer (ManagerImpl* manager) { _debug ("PulseLayer::Pulse audio constructor: Create context\n"); + _urgentRingBuffer.createReadPointer(); } // Destructor @@ -245,7 +246,7 @@ void PulseLayer::closePlaybackStream (void) int PulseLayer::canGetMic() { if (record) - return _micRingBuffer.AvailForGet(); + return 0; // _micRingBuffer.AvailForGet(); else return 0; } @@ -253,7 +254,7 @@ int PulseLayer::canGetMic() int PulseLayer::getMic (void *buffer, int toCopy) { if (record) { - return _micRingBuffer.Get (buffer, toCopy, 100); + return 0; // _micRingBuffer.Get (buffer, toCopy, 100); } else return 0; } @@ -261,9 +262,10 @@ int PulseLayer::getMic (void *buffer, int toCopy) void PulseLayer::startStream (void) { _debug ("PulseLayer::Start stream\n"); + _urgentRingBuffer.flush(); - _micRingBuffer.flush(); - _voiceRingBuffer.flush(); + + _mainBuffer.flush(); pa_threaded_mainloop_lock (m); @@ -288,9 +290,13 @@ PulseLayer::stopStream (void) flushMain(); flushUrgent(); + pa_threaded_mainloop_lock (m); + pa_stream_cork (playback->pulseStream(), 1, NULL, NULL); pa_stream_cork (record->pulseStream(), 1, NULL, NULL); + pa_threaded_mainloop_unlock (m); + isCorked = true; } @@ -349,46 +355,62 @@ void PulseLayer::writeToSpeaker (void) urgentAvail = _urgentRingBuffer.AvailForGet(); if (urgentAvail > 0) { + // Urgent data (dtmf, incoming call signal) come first. //_debug("Play urgent!: %i\e" , urgentAvail); toGet = (urgentAvail < (int) (framesPerBuffer * sizeof (SFLDataFormat))) ? urgentAvail : framesPerBuffer * sizeof (SFLDataFormat); out = (SFLDataFormat*) pa_xmalloc (toGet * sizeof (SFLDataFormat)); _urgentRingBuffer.Get (out, toGet, 100); - pa_stream_write (playback->pulseStream() , out , toGet , pa_xfree, 0 , PA_SEEK_RELATIVE); + pa_stream_write (playback->pulseStream(), out, toGet, NULL, 0, PA_SEEK_RELATIVE); // Consume the regular one as well (same amount of bytes) - _voiceRingBuffer.Discard (toGet); + _mainBuffer.discard (toGet); + + pa_xfree(out); + } else { + AudioLoop* tone = _manager->getTelephoneTone(); if (tone != 0) { + toGet = framesPerBuffer; out = (SFLDataFormat*) pa_xmalloc (toGet * sizeof (SFLDataFormat)); tone->getNext (out, toGet , 100); - pa_stream_write (playback->pulseStream() , out , toGet * sizeof (SFLDataFormat) , pa_xfree, 0 , PA_SEEK_RELATIVE); + pa_stream_write (playback->pulseStream(), out, toGet * sizeof (SFLDataFormat), NULL, 0, PA_SEEK_RELATIVE); + + pa_xfree (out); } if ( (tone=_manager->getTelephoneFile()) != 0) { + toGet = framesPerBuffer; toPlay = ( (int) (toGet * sizeof (SFLDataFormat)) > framesPerBuffer) ? framesPerBuffer : toGet * sizeof (SFLDataFormat) ; out = (SFLDataFormat*) pa_xmalloc (toPlay); tone->getNext (out, toPlay/2 , 100); - pa_stream_write (playback->pulseStream() , out , toPlay , pa_xfree, 0 , PA_SEEK_RELATIVE) ; + pa_stream_write (playback->pulseStream(), out, toPlay, NULL, 0, PA_SEEK_RELATIVE); + + pa_xfree (out); + } else { + out = (SFLDataFormat*) pa_xmalloc (framesPerBuffer * sizeof (SFLDataFormat)); - normalAvail = _voiceRingBuffer.AvailForGet(); + normalAvail = _mainBuffer.availForGet(); toGet = (normalAvail < (int) (framesPerBuffer * sizeof (SFLDataFormat))) ? normalAvail : framesPerBuffer * sizeof (SFLDataFormat); if (toGet) { - _voiceRingBuffer.Get (out, toGet, 100); - _voiceRingBuffer.Discard (toGet); + + _mainBuffer.getData (out, toGet, 100); + pa_stream_write (playback->pulseStream(), out, toGet, NULL, 0, PA_SEEK_RELATIVE); + } else { + bzero (out, framesPerBuffer * sizeof (SFLDataFormat)); } - pa_stream_write (playback->pulseStream() , out , toGet , NULL, 0 , PA_SEEK_RELATIVE); - pa_xfree (out); } + + _urgentRingBuffer.Discard(toGet); } } @@ -403,7 +425,7 @@ void PulseLayer::readFromMic (void) } if (data != 0) { - _micRingBuffer.Put ( (void*) data ,r, 100); + _mainBuffer.putData ( (void*) data ,r, 100); } if (pa_stream_drop (record->pulseStream()) < 0) { diff --git a/sflphone-common/src/audio/recordable.cpp b/sflphone-common/src/audio/recordable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab1bf343aee0bce7cf19b1055ab0a0273ea4bda4 --- /dev/null +++ b/sflphone-common/src/audio/recordable.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2004-2008 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "recordable.h" +#include "manager.h" + +Recordable::Recordable() +{ + + FILE_TYPE fileType = FILE_WAV; + SOUND_FORMAT soundFormat = INT16; + + recAudio.setRecordingOption (fileType, soundFormat, 44100, Manager::instance().getConfigString (AUDIO, RECORD_PATH)); +} + + +Recordable::~Recordable() +{ + if (recAudio.isOpenFile()) { + recAudio.closeFile(); + } +} + + +void Recordable::initRecFileName() +{ + + recAudio.initFileName (getRecFileId()); +} diff --git a/sflphone-common/src/audio/recordable.h b/sflphone-common/src/audio/recordable.h new file mode 100644 index 0000000000000000000000000000000000000000..ece673c903a84107fcd6437e18a863ce596eb0d1 --- /dev/null +++ b/sflphone-common/src/audio/recordable.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2004-2008 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RECORDABLE_H +#define RECORDABLE_H + +#include "../plug-in/audiorecorder/audiorecord.h" + +class Recordable { + + public: + + Recordable(); + + ~Recordable(); + + bool isRecording(){ return recAudio.isRecording(); } + + bool setRecording(){ return recAudio.setRecording(); } + + void stopRecording(){ recAudio.stopRecording(); } + + void initRecFileName(); + + virtual std::string getRecFileId() = 0; + + // virtual std::string getFileName() = 0; + + // std::string getFileName() { return _filename; } + + /** + * An instance of audio recorder + */ + AudioRecord recAudio; + + + private: + + /** File name for his call : time YY-MM-DD */ + // std::string _filename; + + + +}; + +#endif diff --git a/sflphone-common/src/audio/ringbuffer.cpp b/sflphone-common/src/audio/ringbuffer.cpp index ea27fdc23d95e649475dffc45014f7d2ec6179ba..d93a4ed25de8ea85f1ba7f4a68b114dbdc13ea19 100644 --- a/sflphone-common/src/audio/ringbuffer.cpp +++ b/sflphone-common/src/audio/ringbuffer.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2004, 2005, 2006 Savoir-Faire Linux inc. + * Copyright (C) 2004, 2005, 2006, 2009Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> * @@ -29,13 +30,39 @@ #define MIN_BUFFER_SIZE 1280 +int RingBuffer::count_rb = 0; + // Create a ring buffer with 'size' bytes -RingBuffer::RingBuffer (int size) : mStart (0), mEnd (0) +RingBuffer::RingBuffer (int size, CallID call_id) : mEnd (0) , mBufferSize (size > MIN_BUFFER_SIZE ? size : MIN_BUFFER_SIZE) , mBuffer (NULL) + , buffer_id(call_id) { mBuffer = new unsigned char[mBufferSize]; assert (mBuffer != NULL); + + count_rb++; + + // open files + std::string s_input; + std::string s_output; + + // convert count into string + std::stringstream out; + out << count_rb; + + s_input = "/home/alexandresavard/Desktop/buffer_record/buffer_input_"; + s_input.append(out.str()); + + s_output = "/home/alexandresavard/Desktop/buffer_record/buffer_output_"; + s_output.append(out.str()); + + buffer_input_rec = new std::fstream(); + buffer_output_rec = new std::fstream(); + + buffer_input_rec->open(s_input.c_str(), std::fstream::out); + buffer_output_rec->open(s_output.c_str(), std::fstream::out); + } // Free memory on object deletion @@ -43,35 +70,181 @@ RingBuffer::~RingBuffer() { delete[] mBuffer; mBuffer = NULL; + + buffer_input_rec->close(); + delete buffer_input_rec; buffer_input_rec = NULL; + + buffer_output_rec->close(); + delete buffer_output_rec; buffer_output_rec = NULL; } void -RingBuffer::flush (void) +RingBuffer::flush (CallID call_id) +{ + storeReadPointer(mEnd, call_id); +} + +int +RingBuffer::putLen() { - mStart = 0; - mEnd = 0; + int mStart; + + if(_readpointer.size() >= 1) + { + mStart = getSmallestReadPointer(); + } + else + { + mStart = 0; + } + + int length = (mEnd + mBufferSize - mStart) % mBufferSize; + // _debug("RingBuffer::putLen length %i\n", length); + // _debug(" *RingBuffer::putLen: buffer_id %s, mStart %i, mEnd %i, length %i, buffersie %i\n", buffer_id.c_str(), mStart, mEnd, length, mBufferSize); + return length; } int -RingBuffer::Len() const +RingBuffer::getLen(CallID call_id) { + + int mStart = getReadPointer(call_id); + + int length = (mEnd + mBufferSize - mStart) % mBufferSize; + // _debug(" *RingBuffer::getLen: buffer_id %s, call_id %s, mStart %i, mEnd %i, length %i, buffersie %i\n", buffer_id.c_str(), call_id.c_str(), mStart, mEnd, length, mBufferSize); return (mEnd + mBufferSize - mStart) % mBufferSize; + } void RingBuffer::debug() { + int mStart = getSmallestReadPointer(); + _debug ("Start=%d; End=%d; BufferSize=%d\n", mStart, mEnd, mBufferSize); } +int +RingBuffer::getReadPointer(CallID call_id) +{ + + if(getNbReadPointer() == 0) + return 0; + + // _debug("RingBuffer::getReadPointer() id %s\n", call_id.c_str()); + + ReadPointer::iterator iter = _readpointer.find(call_id); + if (iter == _readpointer.end()) + { + // _debug(" RingBuffer::getReadPointer Error read pointer size: %i\n", _readpointer.size()); + // _debug(" RingBuffer::getReadPointer Error read pointer \"%s\" is null\n", call_id.c_str()); + ReadPointer::iterator iter2; + for( iter2 = _readpointer.begin(); iter2 != _readpointer.end(); iter2++) + { + // x_debug(" RingBuffer::getReadPointer list avail pointer \"%s\"\n", iter2->first.c_str()); + } + return 0; + } + else + { + return iter->second; + } + +} + +int +RingBuffer::getSmallestReadPointer() +{ + if (getNbReadPointer() == 0) + return 0; + + int smallest = mBufferSize; + + ReadPointer::iterator iter = _readpointer.begin(); + while (iter != _readpointer.end()) + { + if(iter->second < smallest) + smallest = iter->second; + + iter++; + } + + return smallest; +} + +void +RingBuffer::storeReadPointer(int pointer_value, CallID call_id) +{ + + ReadPointer::iterator iter = _readpointer.find(call_id); + if(iter != _readpointer.end()) + { + iter->second = pointer_value; + // _debug("store read pointer call_id %s, size: %i \n",call_id.c_str(), _readpointer.size()); + } + else + { + _debug("Cannot find \"%s\" readPointer\n", call_id.c_str()); + } + +} + + +void +RingBuffer::createReadPointer(CallID call_id) +{ + + _debug("---- createReadPointer ringbuffer_id %s, call_id %s\n", buffer_id.c_str(), call_id.c_str()); + + _readpointer.insert(pair<CallID, int>(call_id, mEnd)); + _debug("---- createReadPointer ringbuffer_id %s, size %i\n", buffer_id.c_str(),_readpointer.size()); + +} + + +void +RingBuffer::removeReadPointer(CallID call_id) +{ + + _debug("---- removeReadPointer ringbuffer_id %s, call_id %s\n", buffer_id.c_str(), call_id.c_str()); + + _readpointer.erase(call_id); + _debug("---- removeReadPointer ringbuffer_id %s, size %i\n", buffer_id.c_str(), _readpointer.size()); + +} + + +bool +RingBuffer::hasThisReadPointer(CallID call_id) +{ + ReadPointer::iterator iter = _readpointer.find(call_id); + if(iter == _readpointer.end()) + { + return false; + } + else + { + return true; + } +} + + +int +RingBuffer::getNbReadPointer() +{ + return _readpointer.size(); +} + // // For the writer only: // int -RingBuffer::AvailForPut() const +RingBuffer::AvailForPut() { // Always keep 4 bytes safe (?) - return (mBufferSize-4) - Len(); + // z_debug("RingBuffer::AvailForPut: putLen %i\n", putLen()); + // _debug("RingBuffer::AvailForPut %s --------------------\n", buffer_id.c_str()); + return (mBufferSize-4) - putLen(); } // This one puts some data inside the ring buffer. @@ -83,7 +256,9 @@ RingBuffer::Put (void* buffer, int toCopy, unsigned short volume) int block; int copied; int pos; - int len = Len(); + // _debug("RingBuffer::Put buffer_id %s, call_id %s --------------------\n", buffer_id.c_str(), call_id.c_str()); + int len = putLen(); + // _debug(" RingBuffer::Put bufferid %s, putlen %i\n", buffer_id.c_str(), len); if (toCopy > (mBufferSize-4) - len) toCopy = (mBufferSize-4) - len; @@ -117,6 +292,7 @@ RingBuffer::Put (void* buffer, int toCopy, unsigned short volume) // bcopy(src, dest, len) //fprintf(stderr, "has %d put %d\t", len, block); + buffer_input_rec->write((char*)src, block); bcopy (src, mBuffer + pos, block); src += block; @@ -139,20 +315,30 @@ RingBuffer::Put (void* buffer, int toCopy, unsigned short volume) // int -RingBuffer::AvailForGet() const +RingBuffer::AvailForGet(CallID call_id) { // Used space - return Len(); + // _debug("RingBuffer::AvailForGet buffer_id %s, call_id %s --------------------\n", buffer_id.c_str(), call_id.c_str()); + return getLen(call_id); } // Get will move 'toCopy' bytes from the internal FIFO to 'buffer' int -RingBuffer::Get (void *buffer, int toCopy, unsigned short volume) +RingBuffer::Get (void *buffer, int toCopy, unsigned short volume, CallID call_id) { + + if(getNbReadPointer() == 0) + return 0; + + if(!hasThisReadPointer(call_id)) + return 0; + samplePtr dest; int block; int copied; - int len = Len(); + // _debug("RingBuffer::Get buffer_id %s, call_id %s --------------------\n", buffer_id.c_str(), call_id.c_str()); + int len = getLen(call_id); + // _debug(" RingBuffer::Get bufferid %s, getlen %i\n", buffer_id.c_str(), len); if (toCopy > len) toCopy = len; @@ -161,6 +347,8 @@ RingBuffer::Get (void *buffer, int toCopy, unsigned short volume) copied = 0; + int mStart = getReadPointer(call_id); + //fprintf(stderr, "G"); while (toCopy) { block = toCopy; @@ -180,6 +368,7 @@ RingBuffer::Get (void *buffer, int toCopy, unsigned short volume) // bcopy(src, dest, len) bcopy (mBuffer + mStart, dest, block); + buffer_output_rec->write((char*)dest, block); dest += block; @@ -190,19 +379,26 @@ RingBuffer::Get (void *buffer, int toCopy, unsigned short volume) copied += block; } + storeReadPointer(mStart, call_id); + return copied; } // Used to discard some bytes. int -RingBuffer::Discard (int toDiscard) +RingBuffer::Discard (int toDiscard, CallID call_id) { - int len = Len(); + // _debug("RingBuffer::Discard buffer_id %s, call_id %s --------------------\n", buffer_id.c_str(), call_id.c_str()); + int len = getLen(call_id); + + int mStart = getReadPointer(call_id); if (toDiscard > len) toDiscard = len; mStart = (mStart + toDiscard) % mBufferSize; + storeReadPointer(mStart, call_id); + return toDiscard; } diff --git a/sflphone-common/src/audio/ringbuffer.h b/sflphone-common/src/audio/ringbuffer.h index 27db3e31b3deaa8a195c02e1c82a7f876f054418..0dcfbf27e40a811928dbf8aa3ce35c6f01d4413e 100644 --- a/sflphone-common/src/audio/ringbuffer.h +++ b/sflphone-common/src/audio/ringbuffer.h @@ -1,7 +1,8 @@ /* - * Copyright (C) 2004-2005 Savoir-Faire Linux inc. + * Copyright (C) 2004-2009 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> - * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> + * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> * * Portions Copyright (C) Dominic Mazzoni (Audacity) * @@ -23,15 +24,22 @@ #ifndef __RING_BUFFER__ #define __RING_BUFFER__ +#include "../call.h" + +#include <fstream> + + typedef unsigned char* samplePtr; +typedef map<CallID, int> ReadPointer; + class RingBuffer { public: /** * Constructor * @param size Size of the buffer to create */ - RingBuffer(int size); + RingBuffer(int size, CallID call_id); /** * Destructor @@ -42,13 +50,28 @@ class RingBuffer { /** * Reset the counters to 0 */ - void flush (void); + void flush (CallID call_id = default_id); + + + int getReadPointer(CallID call_id = default_id); + + int getSmallestReadPointer(); + + void storeReadPointer(int pointer_value, CallID call_id = default_id); + + void createReadPointer(CallID call_id = default_id); + + void removeReadPointer(CallID call_id = default_id); + + bool hasThisReadPointer(CallID call_id); + + int getNbReadPointer(); /** * To get how much space is available in the buffer to write in * @return int The available size */ - int AvailForPut (void) const; + int AvailForPut (void); /** * Write data in the ring buffer @@ -63,7 +86,7 @@ class RingBuffer { * To get how much space is available in the buffer to read in * @return int The available size */ - int AvailForGet (void) const; + int AvailForGet (CallID call_id = default_id); /** * Get data in the ring buffer @@ -72,20 +95,22 @@ class RingBuffer { * @param volume The volume * @return int Number of bytes copied */ - int Get (void* buffer, int toCopy, unsigned short volume = 100); + int Get (void* buffer, int toCopy, unsigned short volume = 100, CallID call_id = default_id); /** * Discard data from the buffer * @param toDiscard Number of bytes to discard * @return int Number of bytes discarded */ - int Discard(int toDiscard); + int Discard(int toDiscard, CallID call_id = default_id); /** * Total length of the ring buffer * @return int */ - int Len() const; + int putLen(); + + int getLen(CallID call_id = default_id); /** * Debug function print mEnd, mStart, mBufferSize @@ -100,13 +125,28 @@ class RingBuffer { RingBuffer& operator=(const RingBuffer& rh); /** Pointer on the first data */ - int mStart; + // int mStart; /** Pointer on the last data */ int mEnd; /** Buffer size */ int mBufferSize; /** Data */ samplePtr mBuffer; + + ReadPointer _readpointer; + + CallID buffer_id; + + public: + + friend class MainBufferTest; + + std::fstream *buffer_input_rec; + std::fstream *buffer_output_rec; + + static int count_rb; + }; + #endif /* __RING_BUFFER__ */ diff --git a/sflphone-common/src/call.cpp b/sflphone-common/src/call.cpp index b10dcaebda1f4c64f190d8296d6a666f87be6e5b..94a7e79519cfd3294692ec3d5077734147f32041 100644 --- a/sflphone-common/src/call.cpp +++ b/sflphone-common/src/call.cpp @@ -27,6 +27,7 @@ Call::Call (const CallID& id, Call::CallType type) , _localAudioPort (0) , _localExternalAudioPort (0) , _id (id) + , _confID ("") , _type (type) , _connectionState (Call::Disconnected) , _callState (Call::Inactive) @@ -35,18 +36,11 @@ Call::Call (const CallID& id, Call::CallType type) , _peerNumber() { - FILE_TYPE fileType = FILE_WAV; - SOUND_FORMAT soundFormat = INT16; - - recAudio.setRecordingOption (fileType,soundFormat,44100, Manager::instance().getConfigString (AUDIO, RECORD_PATH),id); } Call::~Call() { - if (recAudio.isOpenFile()) { - recAudio.closeFile(); - } } void @@ -134,6 +128,10 @@ Call::getStateStr () break; + case Conferencing: + state_str = "CONFERENCING"; + break; + case Refused: case Error: @@ -175,27 +173,3 @@ Call::isAudioStarted() return _audioStarted; } -void -Call::setRecording() -{ - recAudio.setRecording(); -} - -void -Call::initRecFileName() -{ - recAudio.initFileName (_peerNumber); -} - -void -Call::stopRecording() -{ - recAudio.stopRecording(); -} - -bool -Call::isRecording() -{ - return recAudio.isRecording(); -} - diff --git a/sflphone-common/src/call.h b/sflphone-common/src/call.h index b46f58a6f88cf894208608974741e05349466290..aed0168c90eeb59c9152f3166e17b9e9bd9f7e7e 100644 --- a/sflphone-common/src/call.h +++ b/sflphone-common/src/call.h @@ -24,7 +24,8 @@ #include <cc++/thread.h> // for mutex #include <sstream> -#include "plug-in/audiorecorder/audiorecord.h" +// #include "plug-in/audiorecorder/audiorecord.h" +#include "audio/recordable.h" #define SIP_SCHEME "sip:" #define SIPS_SCHEME "sips:" @@ -38,9 +39,9 @@ typedef std::string CallID; -class AudioRecord; +static CallID default_id = "default_id"; -class Call{ +class Call: public Recordable{ public: /** @@ -67,7 +68,7 @@ class Call{ /** * The Call State. */ - enum CallState {Inactive, Active, Hold, Busy, Refused, Error}; + enum CallState {Inactive, Active, Hold, Busy, Conferencing, Refused, Error}; /** * Constructor of a call @@ -83,6 +84,14 @@ class Call{ */ CallID& getCallId() {return _id; } + /** + * Return a reference on the conference id + * @return call id + */ + CallID& getConfId() {return _confID; } + + void setConfId(CallID id) {_confID = id; } + inline CallType getCallType (void) { return _type; @@ -203,35 +212,9 @@ class Call{ */ unsigned int getLocalAudioPort(); - /** - * @return Return the file name for this call - */ - std::string getFileName() {return _filename;} - - /** - * A recorder for this call - */ - AudioRecord recAudio; - - /** - * SetRecording - */ - void setRecording(); - - /** - * stopRecording, make sure the recording is stopped (whe transfering call) - */ - void stopRecording(); - - /** - * Return Recording state - */ - bool isRecording(); + std::string getRecFileId(){ return getPeerName(); } - /** - * - */ - void initRecFileName(); + std::string getFileName() { return _filename; } protected: /** Protect every attribute that can be changed by two threads */ @@ -256,10 +239,15 @@ class Call{ /** Unique ID of the call */ CallID _id; + /** Unique conference ID, used exclusively in case of a conferece */ + CallID _confID; + /** Type of the call */ CallType _type; + /** Disconnected/Progressing/Trying/Ringing/Connected */ ConnectionState _connectionState; + /** Inactive/Active/Hold/Busy/Refused/Error */ CallState _callState; @@ -272,7 +260,7 @@ class Call{ /** Number of the peer */ std::string _peerNumber; - /** File name for his call : time YY-MM-DD */ + /** File name for his call : time YY-MM-DD */ std::string _filename; }; diff --git a/sflphone-common/src/conference.cpp b/sflphone-common/src/conference.cpp new file mode 100644 index 0000000000000000000000000000000000000000..563dff49037ee6fb20d8f76c952820d4305903cb --- /dev/null +++ b/sflphone-common/src/conference.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author : Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <sstream> + +#include "conference.h" +#include "manager.h" +#include "audio/audiolayer.h" + +int Conference::count = 0; + +Conference::Conference() +{ + _nbParticipant = 0; + + ++count; + + std::string conf("conf_"); + + // convert count into string + std::string s; + std::stringstream out; + out << count; + s = out.str(); + + _nbParticipant = 0; + _id = conf.append(s); + + + +} + + +Conference::~Conference() +{ + + + +} + + +int Conference::getState() +{ + return _confState; +} + + +void Conference::setState(ConferenceState state) +{ + _confState = state; +} + + +void Conference::add(CallID participant_id) +{ + + _debug("---- Conference:: add participant %s\n", participant_id.c_str()); + + _participants.insert(participant_id); + + _nbParticipant++; +} + + +void Conference::remove(CallID participant_id) +{ + + _debug("---- Conference::remove participant %s\n", participant_id.c_str()); + + _participants.erase(participant_id); + + _nbParticipant--; + +} + +void Conference::bindParticipant(CallID participant_id) +{ + + if(_nbParticipant >= 1) { + ParticipantSet::iterator iter = _participants.begin(); + + while (iter != _participants.end()) { + + if (participant_id != (*iter)) { + + _debug("---- Conference:: bind callid %s with %s in conference add\n", participant_id.c_str(), (*iter).c_str()); + Manager::instance().getAudioDriver()->getMainBuffer()->bindCallID(participant_id, *iter); + } + iter++; + } + + } + + _debug("---- Conference::bind callid %s with default_id in conference add\n", participant_id.c_str()); + + Manager::instance().getAudioDriver()->getMainBuffer()->bindCallID(participant_id); + +} + + +std::string Conference::getStateStr() +{ + + std::string state_str; + + switch(_confState) { + + case Active_Atached: + state_str = "ACTIVE_ATACHED"; + break; + + case Active_Detached: + state_str = "ACTIVE_DETACHED"; + break; + + case Hold: + state_str = "HOLD"; + break; + + default: + break; + } + + return state_str; +} + + +ParticipantSet Conference::getParticipantList() +{ + return _participants; +} + diff --git a/sflphone-common/src/conference.h b/sflphone-common/src/conference.h new file mode 100644 index 0000000000000000000000000000000000000000..733b338add7edac43c790bb7a88107a73bf5c5ca --- /dev/null +++ b/sflphone-common/src/conference.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef CONFERENCE_H +#define CONFERENCE_H + +#include <set> +#include <string> + +#include "audio/recordable.h" +#include "call.h" + +// class ManagerImpl; +// class Call; + +typedef std::string ConfID; + +typedef std::set<CallID> ParticipantSet; + +class Conference: public Recordable{ + + public: + + enum ConferenceState {Active_Atached, Active_Detached, Hold}; + + static int count; + + Conference(); + + ~Conference(); + + std::string getConfID() { return _id; } + + int getState(); + + void setState(ConferenceState state); + + std::string getStateStr(); + + int getNbParticipants() { return _nbParticipant; } + + void add(CallID participant_id); + + void remove(CallID participant_id); + + void bindParticipant(CallID participant_id); + + ParticipantSet getParticipantList(); + + std::string getRecFileId(){ return getConfID(); } + + private: + + /** Unique ID of the conference */ + CallID _id; + + ConferenceState _confState; + + ParticipantSet _participants; + + int _nbParticipant; + +}; + +// Conference::count = 0; + +#endif diff --git a/sflphone-common/src/dbus/callmanager-introspec.xml b/sflphone-common/src/dbus/callmanager-introspec.xml index 743dd70f3e1d5803e27b8cbb09ea5cbaec26fe1a..77d48b130c62b371cba633573e4453c1a0100736 100644 --- a/sflphone-common/src/dbus/callmanager-introspec.xml +++ b/sflphone-common/src/dbus/callmanager-introspec.xml @@ -19,6 +19,10 @@ <method name="hangUp"> <arg type="s" name="callID" direction="in"/> </method> + + <method name="hangUpConference"> + <arg type="s" name="confID" direction="in"/> + </method> <method name="hold"> <arg type="s" name="callID" direction="in"/> @@ -52,6 +56,39 @@ <arg type="d" name="value" direction="out"/> </method> + <method name="joinParticipant"> + <arg type="s" name="sel_callID" direction="in"/> + <arg type="s" name="drag_callID" direction="in"/> + </method> + + <method name="addParticipant"> + <arg type="s" name="callID" direction="in"/> + <arg type="s" name="confID" direction="in"/> + </method> + + <method name="addMainParticipant"> + <arg type="s" name="confID" direction="in"/> + </method> + + <method name="detachParticipant"> + <arg type="s" name="callID" direction="in"/> + </method> + + <method name="joinConference"> + <arg type="s" name="sel_confID" direction="in"/> + <arg type="s" name="drag_confID" direction="in"/> + </method> + + <method name="getConferenceDetails"> + <arg type="s" name="callID" direction="in"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="MapStringString"/> + <arg type="a{ss}" name="infos" direction="out"/> + </method> + + <method name="getConferenceList"> + <arg type="as" name="list" direction="out"/> + </method> + <method name="setRecording"> <arg type="s" name="callID" direction="in"/> </method> @@ -100,6 +137,32 @@ <arg type="s" name="callID" direction="out"/> <arg type="s" name="state" direction="out"/> </signal> + + <signal name="conferenceChanged"> + <arg type="s" name="confID" direction="out"/> + <arg type="s" name="state" direction="out"/> + </signal> + + <method name="getParticipantList"> + <arg type="s" name="confID" direction="in"/> + <arg type="as" name="list" direction="out"/> + </method> + + <signal name="conferenceCreated"> + <arg type="s" name="confID" direction="out"/> + </signal> + + <signal name="conferenceRemoved"> + <arg type="s" name="confID" direction="out"/> + </signal> + + <method name="holdConference"> + <arg type="s" name="confID" direction="in"/> + </method> + + <method name="unholdConference"> + <arg type="s" name="confID" direction="in"/> + </method> <signal name="sipCallStateChanged"> <arg type="s" name="callID" direction="out"/> diff --git a/sflphone-common/src/dbus/callmanager.cpp b/sflphone-common/src/dbus/callmanager.cpp index d742a86ae0278bbe291f35f0595b7495a702159b..b069cd2150be2759bf232f259d385ba87f81ed05 100644 --- a/sflphone-common/src/dbus/callmanager.cpp +++ b/sflphone-common/src/dbus/callmanager.cpp @@ -63,15 +63,24 @@ CallManager::accept (const std::string& callID) void CallManager::hangUp (const std::string& callID) { - _debug ("CallManager::hangUp received\n"); + _debug ("CallManager::hangUp received %s\n", callID.c_str()); Manager::instance().hangupCall (callID); } +void +CallManager::hangUpConference (const std::string& confID) +{ + _debug ("CallManager::hangUpConference received %s\n", confID.c_str()); + Manager::instance().hangupConference (confID); + +} + + void CallManager::hold (const std::string& callID) { - _debug ("CallManager::hold received\n"); + _debug ("CallManager::hold received %s\n", callID.c_str()); Manager::instance().onHoldCall (callID); } @@ -79,7 +88,7 @@ CallManager::hold (const std::string& callID) void CallManager::unhold (const std::string& callID) { - _debug ("CallManager::unhold received\n"); + _debug ("CallManager::unhold received %s\n", callID.c_str()); Manager::instance().offHoldCall (callID); } @@ -122,6 +131,75 @@ CallManager::getVolume (const std::string& device) return 0; } +void +CallManager::joinParticipant (const std::string& sel_callID, const std::string& drag_callID) +{ + _debug ("CallManager::joinParticipant received %s, %s\n", sel_callID.c_str(), drag_callID.c_str()); + Manager::instance().joinParticipant(sel_callID, drag_callID); +} + +void +CallManager::addParticipant (const std::string& callID, const std::string& confID) +{ + _debug ("CallManager::addParticipant received %s, %s\n", callID.c_str(), confID.c_str()); + Manager::instance().addParticipant(callID, confID); +} + +void +CallManager::addMainParticipant (const std::string& confID) +{ + _debug ("CallManager::addMainParticipant received %s\n", confID.c_str()); + Manager::instance().addMainParticipant(confID); +} + +void +CallManager::detachParticipant (const std::string& callID) +{ + _debug ("CallManager::detachParticipant received %s\n", callID.c_str()); + Manager::instance().detachParticipant(callID, ""); +} + +void +CallManager::joinConference (const std::string& sel_confID, const std::string& drag_confID) +{ + _debug ("CallManager::joinConference received %s, %s\n", sel_confID.c_str(), drag_confID.c_str()); + Manager::instance().joinConference(sel_confID, drag_confID); +} + +void +CallManager::holdConference (const std::string& confID) +{ + _debug ("CallManager::holdConference received %s\n", confID.c_str()); + Manager::instance().holdConference(confID); +} + +void +CallManager::unholdConference (const std::string& confID) +{ + _debug ("CallManager::unHoldConference received %s\n", confID.c_str()); + Manager::instance().unHoldConference(confID); +} + +std::map< std::string, std::string > +CallManager::getConferenceDetails (const std::string& callID) +{ + _debug ("CallManager::getCallDetails received\n"); + return Manager::instance().getConferenceDetails (callID); +} + +std::vector< std::string > +CallManager::getConferenceList (void) +{ + _debug("CallManager::getConferenceList\n"); + return Manager::instance().getConferenceList(); +} + +std::vector< std::string > +CallManager::getParticipantList (const std::string& confID) +{ + return Manager::instance().getParticipantList(confID); +} + void CallManager::setRecording (const std::string& callID) { @@ -132,7 +210,7 @@ CallManager::setRecording (const std::string& callID) bool CallManager::getIsRecording (const std::string& callID) { - _debug ("CallManager::getIsRecording received \n"); + _debug ("CallManager::getIsRecording received \n"); return Manager::instance().isRecording (callID); } @@ -187,7 +265,7 @@ CallManager::startTone (const int32_t& start , const int32_t& type) // for conferencing in order to get // the right pointer for the given // callID. -sfl::AudioZrtpSession * CallManager::getAudioZrtpSession (void) +sfl::AudioZrtpSession * CallManager::getAudioZrtpSession(const std::string& callID) { SIPVoIPLink * link = NULL; link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink (AccountNULL)); @@ -197,10 +275,10 @@ sfl::AudioZrtpSession * CallManager::getAudioZrtpSession (void) throw CallManagerException(); } + SIPCall *call = link->getSIPCall(callID); + sfl::AudioRtpFactory * audioRtp = NULL; - - audioRtp = link->getAudioRtp(); - + audioRtp = call->getAudioRtp(); if (audioRtp == NULL) { _debug ("Failed to get AudioRtpFactory\n"); throw CallManagerException(); @@ -225,7 +303,7 @@ CallManager::setSASVerified (const std::string& callID) try { sfl::AudioZrtpSession * zSession; - zSession = getAudioZrtpSession(); + zSession = getAudioZrtpSession(callID); zSession->SASVerified(); } catch (...) { throw; @@ -240,7 +318,7 @@ CallManager::resetSASVerified (const std::string& callID) try { sfl::AudioZrtpSession * zSession; - zSession = getAudioZrtpSession(); + zSession = getAudioZrtpSession(callID); zSession->resetSASVerified(); } catch (...) { throw; @@ -255,7 +333,7 @@ CallManager::setConfirmGoClear (const std::string& callID) try { sfl::AudioZrtpSession * zSession; - zSession = getAudioZrtpSession(); + zSession = getAudioZrtpSession(callID); zSession->goClearOk(); } catch (...) { throw; @@ -270,7 +348,7 @@ CallManager::requestGoClear (const std::string& callID) try { sfl::AudioZrtpSession * zSession; - zSession = getAudioZrtpSession(); + zSession = getAudioZrtpSession(callID); zSession->requestGoClear(); } catch (...) { throw; @@ -286,8 +364,8 @@ CallManager::acceptEnrollment (const std::string& callID, const bool& accepted) try { sfl::AudioZrtpSession * zSession; - zSession = getAudioZrtpSession(); - zSession->acceptEnrollment (accepted); + zSession = getAudioZrtpSession(callID); + zSession->acceptEnrollment(accepted); } catch (...) { throw; } @@ -302,8 +380,8 @@ CallManager::setPBXEnrollment (const std::string& callID, const bool& yesNo) try { sfl::AudioZrtpSession * zSession; - zSession = getAudioZrtpSession(); - zSession->setPBXEnrollment (yesNo); + zSession = getAudioZrtpSession(callID); + zSession->setPBXEnrollment(yesNo); } catch (...) { throw; } diff --git a/sflphone-common/src/dbus/callmanager.h b/sflphone-common/src/dbus/callmanager.h index 041ba405d5efbfe3db4edfb373a57386a658b5c8..8c3bab14c0646a373bf83442f2a8035b17ef68e1 100644 --- a/sflphone-common/src/dbus/callmanager.h +++ b/sflphone-common/src/dbus/callmanager.h @@ -50,6 +50,8 @@ class CallManager /* methods exported by this interface, * you will have to implement them in your ObjectAdaptor */ + + /* Call related methods */ void placeCall( const std::string& accountID, const std::string& callID, const std::string& to ); void refuse( const std::string& callID ); void accept( const std::string& callID ); @@ -57,19 +59,33 @@ class CallManager void hold( const std::string& callID ); void unhold( const std::string& callID ); void transfert( const std::string& callID, const std::string& to ); + std::map< std::string, std::string > getCallDetails( const std::string& callID ); + std::vector< std::string > getCallList (void); + std::string getCurrentCallID( ); + + /* Conference related methods */ + void joinParticipant( const std::string& sel_callID, const std::string& drag_callID ); + void addParticipant( const std::string& callID, const std::string& confID ); + void addMainParticipant( const std::string& confID ); + void detachParticipant( const std::string& callID ); + void joinConference( const std::string& sel_confID, const std::string& drag_confID ); + void hangUpConference( const std::string& confID ); + void holdConference( const std::string& confID ); + void unholdConference( const std::string& confID ); + std::vector< std::string > getConferenceList (void); + std::vector< std::string > getParticipantList (const std::string& confID); + std::map< std::string, std::string > getConferenceDetails ( const std::string& callID ); + + /* General audio methods */ void setVolume( const std::string& device, const double& value ); double getVolume( const std::string& device ); void setRecording( const std::string& callID ); bool getIsRecording(const std::string& callID); std::string getCurrentCodecName(const std::string& callID); - - std::map< std::string, std::string > getCallDetails( const std::string& callID ); - std::vector< std::string > getCallList (void); - - std::string getCurrentCallID( ); void playDTMF( const std::string& key ); void startTone( const int32_t& start, const int32_t& type ); + /* Security related methods */ void setSASVerified(const std::string& callID); void resetSASVerified(const std::string& callID); void setConfirmGoClear(const std::string& callID); @@ -79,7 +95,7 @@ class CallManager private: - sfl::AudioZrtpSession * getAudioZrtpSession(void); + sfl::AudioZrtpSession * getAudioZrtpSession(const std::string& callID); }; diff --git a/sflphone-common/src/global.h b/sflphone-common/src/global.h index b8ebe7789fc3b28981603aba8ff010fe326d19ea..12529fe3ef86a7f11f055cee864452d9425e06b2 100644 --- a/sflphone-common/src/global.h +++ b/sflphone-common/src/global.h @@ -90,6 +90,7 @@ static const SOUND_FORMAT INT32 = 0x8; #define CODECDIR "codecs" /** Codecs directory */ #define SIZEBUF 1024*1024 +#define STATIC_BUFSIZE 5000 #define ALSA_DFT_CARD_ID 0 /** Index of the default soundcard */ diff --git a/sflphone-common/src/iax/iaxvoiplink.cpp b/sflphone-common/src/iax/iaxvoiplink.cpp index 2a02e5e87c08e19176fb3ada072fde84050bb557..3faabe566a7fff8cc51445408da73ad4ebe51053 100644 --- a/sflphone-common/src/iax/iaxvoiplink.cpp +++ b/sflphone-common/src/iax/iaxvoiplink.cpp @@ -207,6 +207,8 @@ IAXVoIPLink::getEvent() _mutexIAX.enterMutex(); iax_event* event = NULL; + + while ( (event = iax_get_event (IAX_NONBLOCKING)) != NULL) { // If we received an 'ACK', libiax2 tells apps to ignore them. if (event->etype == IAX_EVENT_NULL) { @@ -238,7 +240,7 @@ IAXVoIPLink::getEvent() if (call) { - call->recAudio.recData (spkrDataConverted,micData,nbSampleForRec_,nbSampleForRec_); + call->recAudio.recData (spkrDataConverted,micData,nbSampleForRec_,nbSampleForRec_); } // Do the doodle-moodle to send audio from the microphone to the IAX channel. @@ -250,8 +252,8 @@ IAXVoIPLink::getEvent() } // reinitialize speaker buffer for recording (when recording a voice mail) - for (int i = 0; i < nbSampleForRec_; i++) - spkrDataConverted[i] = 0; + // for (int i = 0; i < nbSampleForRec_; i++) + // spkrDataConverted[i] = 0; // thread wait 3 millisecond @@ -269,6 +271,8 @@ IAXVoIPLink::sendAudioFromMic (void) AudioCodec *ac; IAXCall *currentCall; + + // We have to update the audio layer type in case we switched // TODO Find out a better way to do it updateAudiolayer(); @@ -276,10 +280,14 @@ IAXVoIPLink::sendAudioFromMic (void) currentCall = getIAXCall (Manager::instance().getCurrentCallId()); if (!currentCall) { + + // Let's mind our own business. return; } + + if (currentCall -> getAudioCodec() < 0) return; @@ -305,15 +313,19 @@ IAXVoIPLink::sendAudioFromMic (void) return; } + + // Send sound here if (audiolayer) { + + // we have to get 20ms of data from the mic *20/1000 = /50 // rate/50 shall be lower than IAX__20S_48KHZ_MAX maxBytesToGet = audiolayer->getSampleRate() * audiolayer->getFrameSize() / 1000 * sizeof (SFLDataFormat); // available bytes inside ringbuffer - availBytesFromMic = audiolayer->canGetMic(); + availBytesFromMic = audiolayer->getMainBuffer()->availForGet(currentCall->getCallId()); if (availBytesFromMic < maxBytesToGet) { // We need packets full! @@ -326,7 +338,9 @@ IAXVoIPLink::sendAudioFromMic (void) //_debug("available = %d, maxBytesToGet = %d\n", availBytesFromMic, maxBytesToGet); // Get bytes from micRingBuffer to data_from_mic - nbSample_ = audiolayer->getMic (micData, bytesAvail) / sizeof (SFLDataFormat); + nbSample_ = audiolayer->getMainBuffer()->getData (micData, bytesAvail, 100, currentCall->getCallId()) / sizeof (SFLDataFormat); + + // Store the number of samples for recording nbSampleForRec_ = nbSample_; @@ -473,6 +487,8 @@ IAXVoIPLink::answer (const CallID& id) IAXCall* call = getIAXCall (id); call->setCodecMap (Manager::instance().getCodecDescriptorMap()); + Manager::instance().addStream(call->getCallId()); + CHK_VALID_CALL; _mutexIAX.enterMutex(); @@ -494,6 +510,9 @@ IAXVoIPLink::hangup (const CallID& id) IAXCall* call = getIAXCall (id); std::string reason = "Dumped Call"; CHK_VALID_CALL; + + audiolayer->getMainBuffer()->unBindAll(call->getCallId()); + _mutexIAX.enterMutex(); iax_hangup (call->getSession(), (char*) reason.c_str()); @@ -519,6 +538,9 @@ IAXVoIPLink::peerHungup (const CallID& id) IAXCall* call = getIAXCall (id); std::string reason = "Dumped Call"; CHK_VALID_CALL; + + audiolayer->getMainBuffer()->unBindAll(call->getCallId()); + _mutexIAX.enterMutex(); _mutexIAX.leaveMutex(); @@ -544,6 +566,8 @@ IAXVoIPLink::onhold (const CallID& id) CHK_VALID_CALL; + audiolayer->getMainBuffer()->unBindAll(call->getCallId()); + //if (call->getState() == Call::Hold) { _debug("Call is already on hold\n"); return false; } _mutexIAX.enterMutex(); @@ -561,6 +585,8 @@ IAXVoIPLink::offhold (const CallID& id) CHK_VALID_CALL; + Manager::instance().addStream(call->getCallId()); + //if (call->getState() == Call::Active) { _debug("Call is already active\n"); return false; } _mutexIAX.enterMutex(); iax_unquelch (call->getSession()); @@ -610,29 +636,6 @@ IAXVoIPLink::refuse (const CallID& id) } -void -IAXVoIPLink::setRecording (const CallID& id) -{ - _debug ("IAXVoIPLink::setRecording()!"); - - IAXCall* call = getIAXCall (id); - - call->setRecording(); -} - -bool -IAXVoIPLink::isRecording (const CallID& id) -{ - _debug ("IAXVoIPLink::setRecording()!"); - - IAXCall* call = getIAXCall (id); - - return call->isRecording(); -} - - - - bool IAXVoIPLink::carryingDTMFdigits (const CallID& id, char code) { @@ -651,11 +654,19 @@ IAXVoIPLink::carryingDTMFdigits (const CallID& id, char code) std::string IAXVoIPLink::getCurrentCodecName() { - IAXCall *call = getIAXCall (Manager::instance().getCurrentCallId()); + IAXCall *call = NULL; + AudioCodec *ac = NULL; + std::string name = ""; + + call = getIAXCall (Manager::instance().getCurrentCallId()); - AudioCodec *ac = call->getCodecMap().getCodec (call->getAudioCodec()); + if(call) + ac = call->getCodecMap().getCodec (call->getAudioCodec()); - return ac->getCodecName(); + if(ac) + name = ac->getCodecName(); + + return name; } @@ -777,6 +788,9 @@ IAXVoIPLink::iaxHandleCallEvent (iax_event* event, IAXCall* call) case IAX_EVENT_ANSWER: if (call->getConnectionState() != Call::Connected) { + + Manager::instance().addStream(call->getCallId()); + call->setConnectionState (Call::Connected); call->setState (Call::Active); audiolayer->startStream(); @@ -858,6 +872,8 @@ IAXVoIPLink::iaxHandleVoiceEvent (iax_event* event, IAXCall* call) int expandedSize, nbSample_; AudioCodec *ac; + + // If we receive datalen == 0, some things of the jitter buffer in libiax2/iax.c // were triggered @@ -867,7 +883,8 @@ IAXVoIPLink::iaxHandleVoiceEvent (iax_event* event, IAXCall* call) return; } - if (audiolayer) { + if (audiolayer) { + // On-the-fly codec changing (normally, when we receive a full packet) // as per http://tools.ietf.org/id/draft-guy-iax-03.txt // - subclass holds the voiceformat property. @@ -905,7 +922,7 @@ IAXVoIPLink::iaxHandleVoiceEvent (iax_event* event, IAXCall* call) nbInt16 = converter->upsampleData (spkrDataDecoded , spkrDataConverted , ac->getClockRate() , audiolayer->getSampleRate() , nbSample_); /* Write the data to the mic ring buffer */ - audiolayer->putMain (spkrDataConverted , nbInt16 * sizeof (SFLDataFormat)); + audiolayer->getMainBuffer()->putData (spkrDataConverted , nbInt16 * sizeof (SFLDataFormat), 100, call->getCallId()); } else { _debug ("IAX: incoming audio, but no sound card open"); @@ -1008,6 +1025,8 @@ IAXVoIPLink::iaxHandlePrecallEvent (iax_event* event) id = Manager::instance().getNewCallID(); + _debug("-------------------------------------------------------------- callid %s", id.c_str()); + call = new IAXCall (id, Call::Incoming); if (!call) { diff --git a/sflphone-common/src/iax/iaxvoiplink.h b/sflphone-common/src/iax/iaxvoiplink.h index a08c40a39a8aa78c9678fb2c25c528cb6d30b509..747cc0509ea08af5d2303041a6fc73d34a97d595 100644 --- a/sflphone-common/src/iax/iaxvoiplink.h +++ b/sflphone-common/src/iax/iaxvoiplink.h @@ -165,18 +165,6 @@ class IAXVoIPLink : public VoIPLink * false otherwise */ bool refuse (const CallID& id); - - /** - * Set Recording - * @param id The call identifier - */ - void setRecording(const CallID& id); - - /** - * Return recording state - * @param id The call identifier - */ - bool isRecording(const CallID& id); /** * Send DTMF diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp index dab69f95cf639a55ee81279812f5c3874ec0514d..46163a25d5ea5ad6fea3e74fe223dced0350a9ad 100644 --- a/sflphone-common/src/managerimpl.cpp +++ b/sflphone-common/src/managerimpl.cpp @@ -4,6 +4,7 @@ * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> * Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify @@ -39,6 +40,8 @@ #include "manager.h" #include "dbus/configurationmanager.h" +#include "conference.h" + #include <errno.h> #include <time.h> #include <cstdlib> @@ -49,6 +52,7 @@ #include <sys/stat.h> // mkdir(2) #include <pwd.h> // getpwuid + #define fill_config_str(name, value) \ (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_str))) #define fill_config_int(name, value) \ @@ -185,7 +189,7 @@ ManagerImpl::isCurrentCall (const CallID& callId) bool ManagerImpl::hasCurrentCall() { - _debug ("Current call ID = %s\n", _currentCallId2.c_str()); + _debug ("ManagerImpl::hasCurrentCall current call ID = %s\n", _currentCallId2.c_str()); if (_currentCallId2 != "") { return true; @@ -204,7 +208,40 @@ void ManagerImpl::switchCall (const CallID& id) { ost::MutexLock m (_currentCallMutex); + _debug("------------------------- SWITCH %s ---------------------------\n", id.c_str()); _currentCallId2 = id; + + /* + AudioLayer *al = getAudioDriver(); + + if (id != "") { + + if(isConference(id)) { + + Conference *conf; + + ConferenceMap::iterator iter = _conferencemap.find(id); + if(iter != _conferencemap.end()) + { + _debug(" set call recordable in audio layer\n"); + conf = iter->second; + al->setRecorderInstance((Recordable*)conf); + } + } + else { + + // set the recordable instance in audiolayer + AccountID account_id = getAccountFromCall(id); + + + Call *call = NULL; + call = getAccountLink (account_id)->getCall(id); + + _debug(" set call recordable in audio layer\n"); + al->setRecorderInstance((Recordable*)call); + } + } + */ } @@ -214,13 +251,15 @@ ManagerImpl::switchCall (const CallID& id) /* Main Thread */ bool -ManagerImpl::outgoingCall (const std::string& accountid, const CallID& id, const std::string& to) +ManagerImpl::outgoingCall (const std::string& account_id, const CallID& call_id, const std::string& to) { std::string pattern, to_cleaned; Call::CallConfiguration callConfig; SIPVoIPLink *siplink; - _debug ("ManagerImpl::outgoingCall() method \n"); + _debug ("ManagerImpl::outgoingCall(%s)\n", call_id.c_str()); + + CallID current_call_id = getCurrentCallId(); if (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ENABLED) == "1") _cleaner->set_phone_number_prefix (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ADD_PREFIX)); @@ -230,47 +269,61 @@ ManagerImpl::outgoingCall (const std::string& accountid, const CallID& id, const to_cleaned = _cleaner->clean (to); /* Check what kind of call we are dealing with */ - check_call_configuration (id, to_cleaned, &callConfig); + check_call_configuration (call_id, to_cleaned, &callConfig); + + // in any cases we have to detach from current communication + if (hasCurrentCall()) { + + _debug (" outgoingCall: Has current call (%s) put it onhold\n", current_call_id.c_str()); + + // if this is not a conferenceand this and is not a conference participant + if (!isConference(current_call_id) && !participToConference(current_call_id)) + { + _debug (" outgoingCall: Put the current call (%s) on hold\n", current_call_id.c_str()); + onHoldCall (current_call_id); + } + else if (isConference(current_call_id) && !participToConference(call_id)) + { + _debug (" outgoingCall: detach main participant from conference\n"); + detachParticipant(default_id, current_call_id); + } + } if (callConfig == Call::IPtoIP) { - _debug ("Start IP to IP call\n"); + _debug (" outgoingCall: Start IP to IP call\n"); /* We need to retrieve the sip voiplink instance */ siplink = SIPVoIPLink::instance (""); - if (siplink->new_ip_to_ip_call (id, to_cleaned)) { - switchCall (id); + if (siplink->new_ip_to_ip_call (call_id, to_cleaned)) { + switchCall (call_id); return true; } else { - callFailure (id); + callFailure (call_id); } return false; } - if (!accountExists (accountid)) { + if (!accountExists (account_id)) { _debug ("! Manager Error: Outgoing Call: account doesn't exist\n"); return false; } - if (getAccountFromCall (id) != AccountNULL) { + if (getAccountFromCall (call_id) != AccountNULL) { _debug ("! Manager Error: Outgoing Call: call id already exists\n"); return false; } - if (hasCurrentCall()) { - _debug ("* Manager Info: there is currently a call, try to hold it\n"); - onHoldCall (getCurrentCallId()); - } - _debug ("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data()); + _debug ("- Manager Action: Adding Outgoing Call %s on account %s\n", call_id.data(), account_id.data()); - associateCallToAccount (id, accountid); + associateCallToAccount (call_id, account_id); - if (getAccountLink (accountid)->newOutgoingCall (id, to_cleaned)) { - switchCall (id); + if (getAccountLink (account_id)->newOutgoingCall (call_id, to_cleaned)) { + switchCall (call_id); return true; } else { - callFailure (id); + callFailure (call_id); _debug ("! Manager Error: An error occur, the call was not created\n"); } @@ -279,126 +332,180 @@ ManagerImpl::outgoingCall (const std::string& accountid, const CallID& id, const //THREAD=Main : for outgoing Call bool -ManagerImpl::answerCall (const CallID& id) +ManagerImpl::answerCall (const CallID& call_id) { - stopTone (true); - - AccountID currentAccountId; - currentAccountId = getAccountFromCall (id); - if (currentAccountId == AccountNULL) { - _debug ("ManagerImpl::answerCall : AccountId is null\n"); - } + _debug("ManagerImpl::answerCall(%s)", call_id.c_str()); - Call* currentCall = NULL; + stopTone (true); - currentCall = getAccountLink (currentAccountId)->getCall (id); + // store the current call id + CallID current_call_id = getCurrentCallId(); - if (currentCall == NULL) { - _debug ("ManagerImpl::answerCall : currentCall is null\n"); + AccountID account_id = getAccountFromCall (call_id); + if(account_id == AccountNULL) { + _debug(" answerCall : AccountId is null\n"); } - - Call* lastCall = NULL; - - if (!getCurrentCallId().empty()) { - lastCall = getAccountLink (currentAccountId)->getCall (getCurrentCallId()); - - if (lastCall == NULL) { - _debug ("ManagerImpl::answerCall : lastCall is null\n"); - } + + Call* call = NULL; + call = getAccountLink (account_id)->getCall (call_id); + if (call == NULL) { + _debug(" answerCall: currentCall is null\n"); } - _debug ("ManagerImpl::answerCall :: current call->getState %i \n", currentCall->getState()); - - _debug ("Try to answer call: %s\n", id.data()); - - if (lastCall != NULL) { - if (lastCall->getState() == Call::Active) { - _debug ("* Manager Info: there is currently a call, try to hold it\n"); - onHoldCall (getCurrentCallId()); - } - } - - if (!getAccountLink (currentAccountId)->answer (id)) { + // in any cases we have to detach from current communication + if (hasCurrentCall()) { + + _debug (" answerCall: Has current call or conference (%s)\n", current_call_id.c_str()); + // if it is not a conference and is not a conference participant + if (!isConference(current_call_id) && !participToConference(current_call_id)) + { + _debug (" answerCall: Put the current call (%s) on hold\n", current_call_id.c_str()); + onHoldCall (current_call_id); + } + // if we are talking to a conference and we are answering an incoming call + else if (isConference(current_call_id) && !participToConference(call_id)) + { + _debug (" answerCall: detach main participant from conference\n"); + detachParticipant(default_id, current_call_id); + } + } + + if (!getAccountLink (account_id)->answer (call_id)) { // error when receiving... - removeCallAccount (id); + removeCallAccount (call_id); return false; } // if it was waiting, it's waiting no more - if (_dbus) _dbus->getCallManager()->callStateChanged (id, "CURRENT"); - - std::string codecName = Manager::instance().getCurrentCodecName (id); + if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "CURRENT"); + + std::string codecName = Manager::instance().getCurrentCodecName (call_id); + if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id, codecName.c_str()); + + removeWaitingCall (call_id); - if (_dbus) _dbus->getCallManager()->currentSelectedCodec (id,codecName.c_str()); - - removeWaitingCall (id); - - switchCall (id); + switchCall (call_id); return true; } //THREAD=Main bool -ManagerImpl::hangupCall (const CallID& id) +ManagerImpl::hangupCall (const CallID& call_id) { - _debug ("ManagerImpl::hangupCall()\n"); + _debug ("ManagerImpl::hangupCall(%s)\n", call_id.c_str()); PulseLayer *pulselayer; - AccountID accountid; + AccountID account_id; bool returnValue; AudioLayer *audiolayer; + // store the current call id + CallID current_call_id = getCurrentCallId(); + stopTone (false); + // switchCall (call_id); /* Broadcast a signal over DBus */ + _debug(" hangupCall: Send DBUS call state change (HUNGUP) for id %s\n", call_id.c_str()); + if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HUNGUP"); - if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP"); - - _debug ("Stop audio stream\n"); + int nbCalls = getCallList().size(); audiolayer = getAudioDriver(); + // stop streamx + if (! (nbCalls >= 1)) + { + _debug(" hangupCall: stop audio stream, ther is only %i call(s) remaining\n", nbCalls); + audiolayer->stopStream(); + } + + if(participToConference(call_id)) + { - int nbCalls = getCallList().size(); + Conference *conf = getConferenceFromCallID(call_id); - _debug ("hangupCall: callList is of size %i call(s)\n", nbCalls); + if(conf != NULL) + { + // remove this participant + removeParticipant(call_id); - // stop stream - if (! (nbCalls > 1)) - audiolayer->stopStream(); + processRemainingParticipant(current_call_id, conf); + } + } + else + { + // we are not participating to a conference, current call switched to "" + if (!isConference(current_call_id)) + switchCall(""); + } /* Direct IP to IP call */ - if (getConfigFromCall (id) == Call::IPtoIP) { - returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (id); + if (getConfigFromCall (call_id) == Call::IPtoIP) { + returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (call_id); } - /* Classic call, attached to an account */ else { - accountid = getAccountFromCall (id); + account_id = getAccountFromCall (call_id); - if (accountid == AccountNULL) { + if (account_id == AccountNULL) + { _debug ("! Manager Hangup Call: Call doesn't exists\n"); return false; } - returnValue = getAccountLink (accountid)->hangup (id); + returnValue = getAccountLink (account_id)->hangup (call_id); - removeCallAccount (id); + removeCallAccount (call_id); } - switchCall (""); - if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) { pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver()); if (pulselayer) pulselayer->restorePulseAppsVolume(); } + return returnValue; +} + +bool +ManagerImpl::hangupConference (const ConfID& id) +{ + _debug ("ManagerImpl::hangupConference()\n"); - return returnValue; + Conference *conf; + ConferenceMap::iterator iter_conf = _conferencemap.find(id); + + AccountID currentAccountId; + + // Call* call = NULL; + + if(iter_conf != _conferencemap.end()) + { + conf = iter_conf->second; + + ParticipantSet participants = conf->getParticipantList(); + ParticipantSet::iterator iter_participant = participants.begin(); + + while(iter_participant != participants.end()) + { + _debug("ManagerImpl::hangupConference participant %s\n", (*iter_participant).c_str()); + + hangupCall (*iter_participant); + + iter_participant++; + + } + + } + + switchCall (""); + + return true; } + //THREAD=Main bool ManagerImpl::cancelCall (const CallID& id) @@ -438,37 +545,38 @@ ManagerImpl::cancelCall (const CallID& id) //THREAD=Main bool -ManagerImpl::onHoldCall (const CallID& id) +ManagerImpl::onHoldCall (const CallID& call_id) { - AccountID accountid; + AccountID account_id; bool returnValue; - CallID call_id; + + _debug("ManagerImpl::onHoldCall(%s)\n", call_id.c_str()); stopTone (true); - call_id = id; + // switchCall (id); /* Direct IP to IP call */ - if (getConfigFromCall (id) == Call::IPtoIP) { - returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (id); + if (getConfigFromCall (call_id) == Call::IPtoIP) { + returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (call_id); } /* Classic call, attached to an account */ else { - accountid = getAccountFromCall (id); + account_id = getAccountFromCall (call_id); - if (accountid == AccountNULL) { - _debug ("Manager On Hold Call: Account ID %s or callid %s doesn't exists\n", accountid.c_str(), id.c_str()); + if (account_id == AccountNULL) { + _debug (" onHoldCall: Account ID %s or callid %s doesn't exists\n", account_id.c_str(), call_id.c_str()); return false; } - returnValue = getAccountLink (accountid)->onhold (id); + returnValue = getAccountLink (account_id)->onhold (call_id); } + + removeWaitingCall (call_id); - removeWaitingCall (id); - - switchCall (""); + // switchCall (""); if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD"); @@ -477,60 +585,88 @@ ManagerImpl::onHoldCall (const CallID& id) //THREAD=Main bool -ManagerImpl::offHoldCall (const CallID& id) +ManagerImpl::offHoldCall (const CallID& call_id) { - AccountID accountid; - bool returnValue, rec; + AccountID account_id; + bool returnValue, is_rec; std::string codecName; - CallID call_id; + + + _debug ("ManagerImpl::offHoldCall(%s)\n", call_id.c_str()); stopTone (false); - call_id = id; - //Place current call on hold if it isn't + CallID current_call_id = getCurrentCallId(); - if (hasCurrentCall()) { - _debug ("Put the current call (ID=%s) on hold\n", getCurrentCallId().c_str()); - onHoldCall (getCurrentCallId()); - } + //Place current call on hold if it isn't + if (hasCurrentCall()) + { + // if this is not a conferenceand this and is not a conference participant + if (!isConference(current_call_id) && !participToConference(current_call_id)) + { + _debug (" offHoldCall: put current call (%s) on hold\n", current_call_id.c_str()); + onHoldCall (current_call_id); + } + else if (isConference(current_call_id) && !participToConference(call_id)) + { + _debug (" offHoldCall Put current conference (%s) on hold\n", current_call_id.c_str()); + detachParticipant(default_id, current_call_id); + } + } + + // switch current call id to id since sipvoip link need it to amke a call + // switchCall(id); /* Direct IP to IP call */ - if (getConfigFromCall (id) == Call::IPtoIP) { - rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (id); - returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (id); + if (getConfigFromCall (call_id) == Call::IPtoIP) { + // is_rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (call_id); + returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (call_id); } /* Classic call, attached to an account */ else { - accountid = getAccountFromCall (id); + account_id = getAccountFromCall (call_id); - if (accountid == AccountNULL) { + if (account_id == AccountNULL) { _debug ("Manager OffHold Call: Call doesn't exists\n"); return false; } - _debug ("Setting OFFHOLD, Account %s, callid %s\n", accountid.c_str(), id.c_str()); + _debug ("Setting OFFHOLD, Account %s, callid %s\n", account_id.c_str(), call_id.c_str()); - rec = getAccountLink (accountid)->isRecording (id); - returnValue = getAccountLink (accountid)->offhold (id); + is_rec = getAccountLink (account_id)->getCall(call_id)->isRecording(); + returnValue = getAccountLink (account_id)->offhold (call_id); } if (_dbus) { - if (rec) + if (is_rec) _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_RECORD"); else _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_CURRENT"); } - switchCall (id); + if ( participToConference(call_id) ) { + + AccountID currentAccountId; + Call* call = NULL; + + currentAccountId = getAccountFromCall (call_id); + call = getAccountLink (currentAccountId)->getCall (call_id); + + switchCall(call->getConfId()); + } + else + { + switchCall(call_id); + } - codecName = getCurrentCodecName (id); + codecName = getCurrentCodecName (call_id); // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str()); - if (_dbus) _dbus->getCallManager()->currentSelectedCodec (id,codecName.c_str()); + if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id,codecName.c_str()); return returnValue; } @@ -627,6 +763,678 @@ ManagerImpl::refuseCall (const CallID& id) return returnValue; } + +Conference* +ManagerImpl::createConference(const CallID& id1, const CallID& id2) +{ + _debug("ManagerImpl::createConference()\n"); + + Conference* conf = new Conference(); + + // _conferencecall.insert(pair<CallID, Conference*>(id1, conf)); + // _conferencecall.insert(pair<CallID, Conference*>(id2, conf)); + _conferencemap.insert(pair<CallID, Conference*>(conf->getConfID(), conf)); + + conf->add(id1); + conf->add(id2); + + // broadcast a signal over dbus + _dbus->getCallManager()->conferenceCreated(conf->getConfID()); + + return conf; +} + +void +ManagerImpl::removeConference(const ConfID& conference_id) +{ + + _debug("ManagerImpl::removeConference(%s)\n", conference_id.c_str()); + + Conference* conf = NULL; + + _debug(" removeConference: _conferencemap.size: %i\n", _conferencemap.size()); + ConferenceMap::iterator iter = _conferencemap.find(conference_id); + + if (iter != _conferencemap.end()) { + _debug(" removeConference: Found conference id %s in conferencemap\n", conference_id.c_str()); + conf = iter->second; + } + + if(conf == NULL) { + + _debug(" removeConference: Error conference not found\n"); + return; + } + + + // We now need to bind the audio to the remain participant + + // unbind main participant from conference (just to be sure) + _audiodriver->getMainBuffer()->unBindAll(default_id); + + ParticipantSet participants = conf->getParticipantList(); + + // bind main participant to remaining conference call + ParticipantSet::iterator iter_p = participants.begin(); + if (iter_p != participants.end()) { + + // to avoid puting onhold the call + // switchCall(""); + _audiodriver->getMainBuffer()->bindCallID(*iter_p, default_id); + } + + // Then remove the conference from the conference map + _debug("ManagerImpl:: remove conference %s\n", conference_id.c_str()); + if (_conferencemap.erase(conference_id) == 1) + _debug("ManagerImpl:: conference %s removed succesfully\n", conference_id.c_str()); + else + _debug("ManagerImpl:: error cannot remove conference id: %s\n", conference_id.c_str()); + + // broadcast a signal over dbus + _debug("ManagerImpl::removeConference broadcast call removed on dbus: %s\n", conference_id.c_str()); + _dbus->getCallManager()->conferenceRemoved(conference_id); + +} + + +Conference* +ManagerImpl::getConferenceFromCallID(const CallID& call_id) +{ + AccountID account_id; + Call* call = NULL; + + account_id = getAccountFromCall (call_id); + call = getAccountLink (account_id)->getCall (call_id); + + ConferenceMap::iterator iter = _conferencemap.find(call->getConfId()); + if(iter != _conferencemap.end()) + { + return iter->second; + } + else + { + return NULL; + } +} + +void +ManagerImpl::holdConference(const CallID& id) +{ + _debug ("ManagerImpl::holdConference()\n"); + + Conference *conf; + ConferenceMap::iterator iter_conf = _conferencemap.find(id); + + AccountID currentAccountId; + + Call* call = NULL; + + if(iter_conf != _conferencemap.end()) + { + conf = iter_conf->second; + + ParticipantSet participants = conf->getParticipantList(); + ParticipantSet::iterator iter_participant = participants.begin(); + + while(iter_participant != participants.end()) + { + _debug(" holdConference: participant %s\n", (*iter_participant).c_str()); + currentAccountId = getAccountFromCall (*iter_participant); + call = getAccountLink (currentAccountId)->getCall (*iter_participant); + + switchCall(*iter_participant); + onHoldCall(*iter_participant); + + iter_participant++; + + } + + conf->setState(Conference::Hold); + + _dbus->getCallManager()->conferenceChanged(conf->getConfID(), conf->getStateStr()); + + } + + + + +} + + +void +ManagerImpl::unHoldConference(const CallID& id) +{ + + _debug ("ManagerImpl::unHoldConference()\n"); + + Conference *conf; + ConferenceMap::iterator iter_conf = _conferencemap.find(id); + + AccountID currentAccountId; + + Call* call = NULL; + + if(iter_conf != _conferencemap.end()) + { + conf = iter_conf->second; + + ParticipantSet participants = conf->getParticipantList(); + ParticipantSet::iterator iter_participant = participants.begin(); + + while(iter_participant != participants.end()) + { + _debug(" unholdConference: participant %s\n", (*iter_participant).c_str()); + currentAccountId = getAccountFromCall (*iter_participant); + call = getAccountLink (currentAccountId)->getCall (*iter_participant); + + offHoldCall(*iter_participant); + + iter_participant++; + + } + + conf->setState(Conference::Active_Atached); + + _dbus->getCallManager()->conferenceChanged(conf->getConfID(), conf->getStateStr()); + + } + +} + +bool +ManagerImpl::isConference(const CallID& id) +{ + ConferenceMap::iterator iter = _conferencemap.find(id); + if(iter == _conferencemap.end()) { + return false; + } + else { + return true; + } +} + +bool +ManagerImpl::participToConference(const CallID& call_id) +{ + + AccountID accountId; + + Call* call = NULL; + + accountId = getAccountFromCall (call_id); + call = getAccountLink (accountId)->getCall(call_id); + + if (call == NULL) + return false; + + if(call->getConfId() == "") { + return false; + } + else { + return true; + } +} + + +void +ManagerImpl::addParticipant(const CallID& call_id, const CallID& conference_id) +{ + _debug("ManagerImpl::addParticipant(%s, %s)\n", call_id.c_str(), conference_id.c_str()); + + std::map<std::string, std::string> call_details = getCallDetails(call_id); + + ConferenceMap::iterator iter = _conferencemap.find(conference_id); + std::map<std::string, std::string>::iterator iter_details; + + // store the current call id (it will change in offHoldCall or in answerCall) + CallID current_call_id = getCurrentCallId(); + + _debug(" addParticipant: enter main process\n"); + if(iter != _conferencemap.end()) { + + Conference* conf = iter->second; + + conf->add(call_id); + + + iter_details = call_details.find("CALL_STATE"); + + switchCall(""); + + _debug(" addParticipant: call state: %s\n", iter_details->second.c_str()); + if (iter_details->second == "HOLD") + { + _debug(" OFFHOLD %s\n", call_id.c_str()); + + // offHoldCall create a new rtp session which use addStream to bind participant + offHoldCall(call_id); + } + else if(iter_details->second == "INCOMING") + { + _debug(" ANSWER %s\n", call_id.c_str()); + // answerCall create a new rtp session which use addStream to bind participant + answerCall(call_id); + } + else if(iter_details->second == "CURRENT") + { + // Already a curent call, so we beed to reset audio stream bindings manually + _audiodriver->getMainBuffer()->unBindAll(call_id); + conf->bindParticipant(call_id); + } + + // update this call conference id + AccountID currentAccountId; + + Call* call = NULL; + + currentAccountId = getAccountFromCall (call_id); + call = getAccountLink (currentAccountId)->getCall (call_id); + call->setConfId (conf->getConfID()); + + _dbus->getCallManager()->conferenceChanged(conference_id, conf->getStateStr()); + } + { + _debug(" addParticipant: Error, conference %s conference_id not found!\n", conference_id.c_str()); + } + + + // bind main participant to conference after adding new participant + detachParticipant(default_id, current_call_id); + + // to avoid puting onhold the added call + switchCall(""); + addMainParticipant(conference_id); + + + + +} + +void +ManagerImpl::addMainParticipant(const CallID& conference_id) +{ + if(hasCurrentCall()) + { + CallID current_call_id = getCurrentCallId(); + + if(isConference(current_call_id)) + { + detachParticipant(default_id, current_call_id); + } + else + { + onHoldCall(current_call_id); + } + } + + ConferenceMap::iterator iter = _conferencemap.find(conference_id); + + Conference *conf = NULL; + + if(iter != _conferencemap.end()) + { + conf = iter->second; + + ParticipantSet participants = conf->getParticipantList(); + + ParticipantSet::iterator iter_participant = participants.begin(); + while(iter_participant != participants.end()) + { + _audiodriver->getMainBuffer()->bindCallID(*iter_participant, default_id); + + iter_participant++; + } + + conf->setState(Conference::Active_Atached); + + _dbus->getCallManager()->conferenceChanged(conference_id, conf->getStateStr()); + + } + + switchCall(conference_id); +} + + +void +ManagerImpl::joinParticipant(const CallID& call_id1, const CallID& call_id2) +{ + _debug("ManagerImpl::joinParticipant(%s, %s)\n", call_id1.c_str(), call_id2.c_str()); + // _debug(" Current call ID %s\n", getCurrentCallId().c_str()); + + std::map<std::string, std::string> call1_details = getCallDetails(call_id1); + std::map<std::string, std::string> call2_details = getCallDetails(call_id2); + + ConferenceMap::iterator iter = _conferencemap.find(default_conf); + std::map<std::string, std::string>::iterator iter_details; + + AccountID currentAccountId; + Call* call = NULL; + + CallID current_call_id = getCurrentCallId(); + _debug(" joinParticipant: current_call_id %s\n", current_call_id.c_str()); + + + // detach from the conference and switch to this conference + if ((current_call_id != call_id1) && (current_call_id != call_id2)) + { + if (isConference(current_call_id)) + detachParticipant(default_id, current_call_id); + else + onHoldCall(current_call_id); + } + + if(iter == _conferencemap.end()){ + + _debug(" joinParticipant: create a conference\n"); + Conference *conf = createConference(call_id1, call_id2); + + // AccountID currentAccountId; + // Call* call = NULL; + + // unbind main participant from either call_id1 or call_id2 + // _audiodriver->getMainBuffer()->unBindAll(default_id); + + switchCall(""); + + iter_details = call1_details.find("CALL_STATE"); + _debug(" joinParticipant: call1 %s state: %s\n", call_id1.c_str(), iter_details->second.c_str()); + if (iter_details->second == "HOLD") + { + _debug(" OFFHOLD %s\n", call_id1.c_str()); + offHoldCall(call_id1); + } + else if(iter_details->second == "INCOMING") + { + _debug(" ANSWER %s\n", call_id1.c_str()); + answerCall(call_id1); + } + else if(iter_details->second == "CURRENT") + { + _debug(" CURRENT %s\n", call_id1.c_str()); + _audiodriver->getMainBuffer()->unBindAll(call_id1); + conf->bindParticipant(call_id1); + } + + currentAccountId = getAccountFromCall (call_id1); + call = getAccountLink (currentAccountId)->getCall (call_id1); + call->setConfId (conf->getConfID()); + + + switchCall(""); + + iter_details = call2_details.find("CALL_STATE"); + _debug(" joinParticipant: call2 %s state: %s\n", call_id2.c_str(), iter_details->second.c_str()); + if (iter_details->second == "HOLD") + { + _debug(" OFFHOLD %s\n", call_id2.c_str()); + offHoldCall (call_id2); + } + else if(iter_details->second == "INCOMING") + { + _debug(" ANSWER %s\n", call_id2.c_str()); + answerCall(call_id2); + } + else if(iter_details->second == "CURRENT") + { + _debug(" CURRENT %s\n", call_id2.c_str()); + _audiodriver->getMainBuffer()->unBindAll(call_id2); + conf->bindParticipant(call_id2); + } + + currentAccountId = getAccountFromCall (call_id2); + call = getAccountLink (currentAccountId)->getCall (call_id2); + call->setConfId (conf->getConfID()); + + + // finally bind main participant to conference + // addMainParticipant(default_conf); + + + switchCall(conf->getConfID()); + + } + else { + + _debug("ManagerImpl::joinParticipant already a conference created with this ID\n"); + + } + +} + + +void +ManagerImpl::detachParticipant(const CallID& call_id, const CallID& current_id) +{ + _debug("ManagerImpl::detachParticipant(%s)\n", call_id.c_str()); + + CallID current_call_id = current_id; + + if(current_call_id.compare("") == 0); + current_call_id = getCurrentCallId(); + + if(call_id != default_id) + { + AccountID currentAccountId; + Call* call = NULL; + + currentAccountId = getAccountFromCall (call_id); + call = getAccountLink (currentAccountId)->getCall (call_id); + + // TODO: add conference_id as a second parameter + ConferenceMap::iterator iter = _conferencemap.find(call->getConfId()); + + Conference *conf = getConferenceFromCallID(call_id); + + if(conf != NULL) { + + _debug(" detachParticipant: detaching participant %s\n", call_id.c_str()); + + std::map<std::string, std::string> call_details = getCallDetails(call_id); + std::map<std::string, std::string>::iterator iter_details; + + iter_details = call_details.find("CALL_STATE"); + if (iter_details->second == "RINGING") + { + removeParticipant(call_id); + } + else + { + _debug(" ONHOLD %s\n", call_id.c_str()); + onHoldCall(call_id); + + removeParticipant(call_id); + + processRemainingParticipant(current_call_id, conf); + } + } + else { + + + _debug(" detachParticipant: call is not conferencing, cannot detach\n"); + + } + } + else + { + _debug(" detachParticipant: unbind main participant from all\n"); + _audiodriver->getMainBuffer()->unBindAll(default_id); + + if( isConference(current_call_id) ) + { + + ConferenceMap::iterator iter = _conferencemap.find(current_call_id); + Conference *conf = iter->second; + + conf->setState(Conference::Active_Detached); + + _dbus->getCallManager()->conferenceChanged(conf->getConfID(), conf->getStateStr()); + } + + } + +} + + +void +ManagerImpl::removeParticipant(const CallID& call_id) +{ + _debug("ManagerImpl::removeParticipant(%s)\n", call_id.c_str()); + + // TODO: add conference_id as a second parameter + Conference* conf; + + AccountID currentAccountId; + Call* call = NULL; + + // this call is no more a conference participant + currentAccountId = getAccountFromCall (call_id); + call = getAccountLink (currentAccountId)->getCall (call_id); + + ConferenceMap conf_map = _conferencemap; + ConferenceMap::iterator iter = conf_map.find(call->getConfId()); + + if(iter == conf_map.end()) { + _debug(" no conference created, cannot remove participant \n"); + } + else { + + conf = iter->second; + + _debug(" removeParticipant %s\n", call_id.c_str()); + conf->remove(call_id); + call->setConfId (""); + + } + +} + + +void +ManagerImpl::processRemainingParticipant(CallID current_call_id, Conference *conf) +{ + + _debug("ManagerImpl::processRemainingParticipant()\n"); + + if(conf->getNbParticipants() > 1) + { + + } + else if (conf->getNbParticipants() == 1) + { + AccountID currentAccountId; + Call* call = NULL; + + ParticipantSet participants = conf->getParticipantList(); + ParticipantSet::iterator iter_participant = participants.begin(); + + // bind main participant to remaining conference call + if (iter_participant != participants.end()) { + + // this call is no more a conference participant + currentAccountId = getAccountFromCall (*iter_participant); + call = getAccountLink (currentAccountId)->getCall (*iter_participant); + call->setConfId (""); + + // if we are not listening to this conference + if (current_call_id != conf->getConfID()) + { + onHoldCall(call->getCallId()); + } + else + { + switchCall(*iter_participant); + } + } + + removeConference(conf->getConfID()); + } + else + { + removeConference(conf->getConfID()); + + switchCall(""); + } + +} + +void +ManagerImpl::joinConference(const CallID& conf_id1, const CallID& conf_id2) +{ + _debug("ManagerImpl::joinConference(%s, %s)\n", conf_id1.c_str(), conf_id2.c_str()); + + ConferenceMap::iterator iter; + + Conference *conf1 = NULL; + Conference *conf2 = NULL; + + iter = _conferencemap.find(conf_id1); + + if(iter != _conferencemap.end()) + conf1 = iter->second; + + iter = _conferencemap.find(conf_id2); + + if(iter != _conferencemap.end()) + conf2 = iter->second; + + ParticipantSet participants = conf1->getParticipantList(); + + ParticipantSet::iterator iter_participant = participants.begin(); + + while(iter_participant != participants.end()) + { + detachParticipant(*iter_participant, ""); + addParticipant(*iter_participant, conf_id2); + + iter_participant++; + } + + // detachParticipant(default_id, ""); + +} + +void +ManagerImpl::addStream(const CallID& call_id) +{ + _debug("ManagerImpl::addStream %s\n", call_id.c_str()); + + AccountID currentAccountId; + Call* call = NULL; + + currentAccountId = getAccountFromCall (call_id); + call = getAccountLink (currentAccountId)->getCall (call_id); + + if(participToConference(call_id)) { + + // bind to conference participant + ConferenceMap::iterator iter = _conferencemap.find(call->getConfId()); + if (iter != _conferencemap.end()) + { + Conference* conf = iter->second; + + conf->bindParticipant(call_id); + } + } + else { + + // bind to main + getAudioDriver()->getMainBuffer()->bindCallID(call_id); + } +} + +void +ManagerImpl::removeStream(const CallID& call_id) +{ + _debug("ManagerImpl::removeStream %s\n", call_id.c_str()); + + getAudioDriver()->getMainBuffer()->unBindAll(call_id); + + if(participToConference(call_id)) { + removeParticipant(call_id); + } + +} + //THREAD=Main bool ManagerImpl::saveConfig (void) @@ -685,7 +1493,6 @@ ManagerImpl::sendDtmf (const CallID& id, char code) AccountID accountid = getAccountFromCall (id); if (accountid == AccountNULL) { - //_debug("Send DTMF: call doesn't exists\n"); playDtmf (code, false); return false; } @@ -728,13 +1535,19 @@ ManagerImpl::playDtmf (char code, bool isTalking) bool hasToPlayTone = getConfigBool (SIGNALISATION, PLAY_DTMF); if (!hasToPlayTone) + { + _debug(" playDtmf: Do not have to play a tone...\n"); return false; + } // length in milliseconds pulselen = getConfigInt (SIGNALISATION, PULSE_LENGTH); if (!pulselen) + { + _debug(" playDtmf: Pulse length is not set...\n"); return false; + } // numbers of int = length in milliseconds / 1000 (number of seconds) // = number of seconds * SAMPLING_RATE by SECONDS @@ -744,13 +1557,16 @@ ManagerImpl::playDtmf (char code, bool isTalking) // fast return, no sound, so no dtmf if (audiolayer==0 || _dtmfKey == 0) + { + _debug(" playDtmf: Error no audio layer...\n"); return false; + } // number of data sampling in one pulselen depends on samplerate // size (n sampling) = time_ms * sampling/s // --------------------- // ms/s - size = (int) (pulselen * ( (float) audiolayer->getSampleRate() /1000)); + size = (int) ((pulselen * (float) audiolayer->getSampleRate()) / 1000); // this buffer is for mono // TODO <-- this should be global and hide if same size @@ -767,6 +1583,9 @@ ManagerImpl::playDtmf (char code, bool isTalking) audiolayer->startStream(); audiolayer->putUrgent (buf, size * sizeof (SFLDataFormat)); } + else { + _debug(" playDtmf: Error cannot play dtmf\n"); + } ret = true; @@ -835,12 +1654,12 @@ ManagerImpl::incomingCall (Call* call, const AccountID& accountId) if (accountId==AccountNULL) associateConfigToCall (call->getCallId(), Call::IPtoIP); - _debug ("ManagerImpl::incomingCall :: hasCurrentCall() %i \n",hasCurrentCall()); + _debug ("ManagerImpl::incomingCall :: hasCurrentCall() %i \n", hasCurrentCall()); if (!hasCurrentCall()) { call->setConnectionState (Call::Ringing); ringtone(); - switchCall (call->getCallId()); + // switchCall (call->getCallId()); } @@ -928,40 +1747,63 @@ ManagerImpl::peerRingingCall (const CallID& id) //THREAD=VoIP Call=Outgoing/Ingoing void -ManagerImpl::peerHungupCall (const CallID& id) +ManagerImpl::peerHungupCall (const CallID& call_id) { PulseLayer *pulselayer; - AccountID accountid; + AccountID account_id; bool returnValue; - /* Direct IP to IP call */ + _debug("ManagerImpl::peerHungupCall(%s)\n", call_id.c_str()); - if (getConfigFromCall (id) == Call::IPtoIP) { - SIPVoIPLink::instance (AccountNULL)->hangup (id); + // store the current call id + CallID current_call_id = getCurrentCallId(); + + + if(participToConference(call_id)) + { + + Conference *conf = getConferenceFromCallID(call_id); + + if(conf != NULL) + { + + removeParticipant(call_id); + + processRemainingParticipant(current_call_id, conf); + } + } + else + { + if (isCurrentCall(call_id)) + { + stopTone (true); + switchCall (""); + } + } + + /* Direct IP to IP call */ + if (getConfigFromCall (call_id) == Call::IPtoIP) { + SIPVoIPLink::instance (AccountNULL)->hangup (call_id); } else { - accountid = getAccountFromCall (id); - if (accountid == AccountNULL) { + account_id = getAccountFromCall (call_id); + + if (account_id == AccountNULL) { _debug ("peerHungupCall: Call doesn't exists\n"); return; } - returnValue = getAccountLink (accountid)->peerHungup (id); + returnValue = getAccountLink (account_id)->peerHungup (call_id); } /* Broadcast a signal over DBus */ - if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP"); - - if (isCurrentCall (id)) { - stopTone (true); - switchCall (""); - } + if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HUNGUP"); - removeWaitingCall (id); + removeWaitingCall (call_id); - removeCallAccount (id); + removeCallAccount (call_id); if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) { pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver()); @@ -1873,19 +2715,32 @@ ManagerImpl::setVolumeControls (void) void ManagerImpl::setRecordingCall (const CallID& id) { + /* _debug ("ManagerImpl::setRecording()! \n"); AccountID accountid = getAccountFromCall (id); getAccountLink (accountid)->setRecording (id); + */ + AccountID accountid = getAccountFromCall (id); + Recordable* rec = (Recordable*)getAccountLink (accountid)->getCall(id); + + rec->setRecording(); } bool ManagerImpl::isRecording (const CallID& id) { + /* _debug ("ManagerImpl::isRecording()! \n"); AccountID accountid = getAccountFromCall (id); return getAccountLink (accountid)->isRecording (id); + */ + + AccountID accountid = getAccountFromCall (id); + Recordable* rec = (Recordable*)getAccountLink (accountid)->getCall(id); + + return rec->isRecording(); } void @@ -2321,6 +3176,7 @@ ManagerImpl::getCallStatus (const std::string& sequenceId UNUSED) switch (call->getState()) { case Call::Active: + case Call::Conferencing: code="112"; status = "Established"; break; @@ -3626,3 +4482,68 @@ ManagerImpl::getCallList (void) return v; } + + +std::map< std::string, std::string > +ManagerImpl::getConferenceDetails(const ConfID& confID) +{ + + std::map<std::string, std::string> conf_details; + ConferenceMap::iterator iter_conf; + + iter_conf = _conferencemap.find(confID); + + Conference *conf = NULL; + if(iter_conf != _conferencemap.end()) { + + + conf_details.insert (std::pair<std::string, std::string> ("CONFID", confID)); + conf_details.insert (std::pair<std::string, std::string> ("CONF_STATE", conf->getStateStr())); + } + + return conf_details; +} + + +std::vector< std::string > +ManagerImpl::getConferenceList (void) +{ + _debug("ManagerImpl::getConferenceList\n"); + std::vector< std::string > v; + + ConferenceMap::iterator iter = _conferencemap.begin(); + while (iter != _conferencemap.end ()) { + v.push_back (iter->first); + iter++; + } + + return v; +} + + +std::vector< std::string > +ManagerImpl::getParticipantList (const std::string& confID) +{ + _debug("ManagerImpl::getParticipantList\n"); + std::vector< std::string > v; + + ConferenceMap::iterator iter_conf = _conferencemap.find(confID); + Conference *conf = NULL; + if(iter_conf != _conferencemap.end()) + conf = iter_conf->second; + + if(conf != NULL) + { + ParticipantSet participants = conf->getParticipantList(); + ParticipantSet::iterator iter_participant = participants.begin(); + while (iter_participant != participants.end ()) { + + v.push_back (*iter_participant); + + iter_participant++; + } + } + + return v; +} + diff --git a/sflphone-common/src/managerimpl.h b/sflphone-common/src/managerimpl.h index d5c2c1d3b0a00d3e7f3d2c5934b74ca0f4b0020f..bf25eecd1466af17b2a13fb08d0f914e36dcb524 100644 --- a/sflphone-common/src/managerimpl.h +++ b/sflphone-common/src/managerimpl.h @@ -35,6 +35,7 @@ #include "account.h" #include "call.h" +#include "conference.h" #include "numbercleaner.h" #include "audio/sound/tonelist.h" // for Tone::TONEID declaration @@ -46,6 +47,13 @@ class AudioLayer; class GuiFramework; class TelephoneTone; class VoIPLink; + +// class Conference; + +#ifdef USE_ZEROCONF +class DNSService; +#endif + class HistoryManager; class SIPAccount; @@ -63,6 +71,16 @@ typedef std::set<CallID> CallIDSet; /** To send multiple string */ typedef std::list<std::string> TokenList; +/** To store conference objects by call ids + used to retreive the conference according to a call */ +typedef std::map<CallID, Conference*> ConferenceCallMap; + +/** To store conference objects by conference ids */ +typedef std::map<CallID, Conference*> ConferenceMap; + +static CallID default_conf = "conf"; + + static char * mapStateToChar[] = { (char*) "UNREGISTERED", (char*) "TRYING", @@ -136,6 +154,14 @@ class ManagerImpl { */ bool hangupCall(const CallID& id); + + /** + * Functions which occur with a user's action + * Hangup the conference (hangup every participants) + * @param id The call identifier + */ + bool hangupConference(const ConfID& id); + /** * Functions which occur with a user's action * Cancel the call @@ -182,6 +208,38 @@ class ManagerImpl { */ bool refuseCall(const CallID& id); + Conference* createConference(const CallID& id1, const CallID& id2); + + void removeConference(const CallID& conference_id); + + Conference* getConferenceFromCallID(const CallID& call_id); + + void holdConference(const CallID& conferece_id); + + void unHoldConference(const CallID& conference_id); + + bool isConference(const CallID& call_id); + + bool participToConference(const CallID& call_id); + + void addParticipant(const CallID& call_id, const CallID& conference_id); + + void addMainParticipant(const CallID& conference_id); + + void joinParticipant(const CallID& call_id1, const CallID& call_id2); + + void detachParticipant(const CallID& call_id, const CallID& current_call_id); + + void removeParticipant(const CallID& call_id); + + void processRemainingParticipant(CallID current_call_id, Conference *conf); + + void joinConference(const CallID& conf_id1, const CallID& conf_id2); + + void addStream(const CallID& call_id); + + void removeStream(const CallID& call_id); + /** * Save config to file * @return true on success @@ -325,6 +383,26 @@ class ManagerImpl { */ std::vector< std::string > getCallList (void); + /** + * Retrieve details about a given call + * @param callID The account identifier + * @return std::map< std::string, std::string > The call details + */ + std::map< std::string, std::string > getConferenceDetails(const CallID& callID); + + /** + * Get call list + * @return std::vector<std::string> A list of call IDs + */ + std::vector< std::string > getConferenceList (void); + + + /** + * Get a list of participant to a conference + * @return std::vector<std::string> A list of call IDs + */ + std::vector< std::string > getParticipantList (const std::string& confID); + /** * Save the details of an existing account, given the account ID * This will load the configuration map with the given data. @@ -1167,6 +1245,13 @@ class ManagerImpl { int isStunEnabled (void); void enableStun (void); + + // Map + ConferenceCallMap _conferencecall; + + // + ConferenceMap _conferencemap; + private: // Copy Constructor diff --git a/sflphone-common/src/plug-in/audiorecorder/audiorecord.cpp b/sflphone-common/src/plug-in/audiorecorder/audiorecord.cpp index dc4bfa1b1eb0a800c9cb1e703830ac8edd429f82..466b6daffb0ade81a9e6a78baf42071b90d04938 100644 --- a/sflphone-common/src/plug-in/audiorecorder/audiorecord.cpp +++ b/sflphone-common/src/plug-in/audiorecorder/audiorecord.cpp @@ -68,7 +68,7 @@ void AudioRecord::setSndSamplingRate (int smplRate) sndSmplRate_ = smplRate; } -void AudioRecord::setRecordingOption (FILE_TYPE type, SOUND_FORMAT format, int sndSmplRate, std::string path, std::string id) +void AudioRecord::setRecordingOption (FILE_TYPE type, SOUND_FORMAT format, int sndSmplRate, std::string path) { @@ -76,7 +76,6 @@ void AudioRecord::setRecordingOption (FILE_TYPE type, SOUND_FORMAT format, int s sndFormat_ = format; channels_ = 1; sndSmplRate_ = sndSmplRate; - call_id_ = id; savePath_ = path + "/"; diff --git a/sflphone-common/src/plug-in/audiorecorder/audiorecord.h b/sflphone-common/src/plug-in/audiorecorder/audiorecord.h index 679625090403ac097ff40d1da5a64feb1aa86658..de61da019c6b24a4ca05df58025deeeeb03ae1ca 100644 --- a/sflphone-common/src/plug-in/audiorecorder/audiorecord.h +++ b/sflphone-common/src/plug-in/audiorecorder/audiorecord.h @@ -45,7 +45,7 @@ public: void setSndSamplingRate(int smplRate); - void setRecordingOption(FILE_TYPE type, SOUND_FORMAT format, int sndSmplRate, std::string path, std::string id); + void setRecordingOption(FILE_TYPE type, SOUND_FORMAT format, int sndSmplRate, std::string path); void initFileName( std::string peerNumber ); @@ -226,11 +226,6 @@ protected: * Path for this recording */ std::string savePath_; - - /** - * Path for this recordingId for this call - */ - std::string call_id_; }; diff --git a/sflphone-common/src/sip/sdp.cpp b/sflphone-common/src/sip/sdp.cpp index d7be80a83a33a2467921497e7a2f9d86bea648ac..489e042cf606ad688825c63e90ce59c1f3febdb0 100644 --- a/sflphone-common/src/sip/sdp.cpp +++ b/sflphone-common/src/sip/sdp.cpp @@ -177,16 +177,24 @@ int Sdp::create_initial_offer() status = create_local_offer(); if (status != PJ_SUCCESS) { + _debug (" Error: Failled to create initial offer\n"); return status; } // Create the SDP negociator instance with local offer status = pjmedia_sdp_neg_create_w_local_offer (_pool, get_local_sdp_session(), &_negociator); + if (status != PJ_SUCCESS) { + _debug (" Error: Failled to create an initial SDP negociator\n"); + return status; + } + state = pjmedia_sdp_neg_get_state (_negociator); PJ_ASSERT_RETURN (status == PJ_SUCCESS, 1); + _debug (" Initial offer created succesfully\n"); + return PJ_SUCCESS; } diff --git a/sflphone-common/src/sip/sipcall.cpp b/sflphone-common/src/sip/sipcall.cpp index e3c71e3fbf4c6aa1ed325e0cbc0a9e0ae1ed719c..81451d591362ba448aacd0428734d5f58165eefe 100644 --- a/sflphone-common/src/sip/sipcall.cpp +++ b/sflphone-common/src/sip/sipcall.cpp @@ -28,6 +28,7 @@ SIPCall::SIPCall (const CallID& id, Call::CallType type, pj_pool_t *pool) : Call , _cid (0) , _did (0) , _tid (0) + , _audiortp (new sfl::AudioRtpFactory()) , _xferSub (NULL) , _invSession (NULL) , _local_sdp (0) @@ -38,7 +39,8 @@ SIPCall::SIPCall (const CallID& id, Call::CallType type, pj_pool_t *pool) : Call SIPCall::~SIPCall() { - + delete _audiortp; + _audiortp = 0; delete _local_sdp; _local_sdp = 0; _debug ("SIPCALL::Destructor for this class is called \n"); diff --git a/sflphone-common/src/sip/sipcall.h b/sflphone-common/src/sip/sipcall.h index 8476febb57992d9b08f16229fd14d04cce3a9033..f2d93259da6872000a51a3491da79e2d37eef3b4 100644 --- a/sflphone-common/src/sip/sipcall.h +++ b/sflphone-common/src/sip/sipcall.h @@ -26,8 +26,15 @@ #include <pjsip-simple/evsub.h> #include <pjsip_ua.h> +#include "audio/audiortp/AudioRtpFactory.h" + class AudioCodec; class Sdp; +class AudioRtp; + +namespace sfl { + class AudioRtpFactory; +} /** * @file sipcall.h @@ -79,6 +86,8 @@ class SIPCall : public Call * @return int SIP transaction id */ int getTid() { return _tid; } + + /** @@ -97,6 +106,9 @@ class SIPCall : public Call void setLocalSDP (Sdp *local_sdp) { _local_sdp = local_sdp; } + /** Returns a pointer to the AudioRtp object */ + inline sfl::AudioRtpFactory * getAudioRtp(void) { return _audiortp; } + private: int _cid; @@ -108,8 +120,10 @@ class SIPCall : public Call // Assignment Operator SIPCall& operator=( const SIPCall& rh); - - + + /** Starting sound */ + sfl::AudioRtpFactory * _audiortp; + pjsip_evsub *_xferSub; pjsip_inv_session *_invSession; diff --git a/sflphone-common/src/sip/sipvoiplink.cpp b/sflphone-common/src/sip/sipvoiplink.cpp index a9aa8bbe3db864bcea4d7f45f3b461937bd7fb0d..be814b18afee2ec44ae9c6a4bd97ee06110592f4 100644 --- a/sflphone-common/src/sip/sipvoiplink.cpp +++ b/sflphone-common/src/sip/sipvoiplink.cpp @@ -161,7 +161,7 @@ void call_on_state_changed (pjsip_inv_session *inv, pjsip_event *e); * @param inv A pointer on a pjsip_inv_session structure * @param status A pj_status_t structure */ -void call_on_media_update (pjsip_inv_session *inv UNUSED, pj_status_t status UNUSED); +void call_on_media_update (pjsip_inv_session *inv, pj_status_t status UNUSED); /* * Called when the invite usage module has created a new dialog and invite @@ -226,8 +226,7 @@ SIPVoIPLink::SIPVoIPLink (const AccountID& accountID) , _nbTryListenAddr (2) // number of times to try to start SIP listener , _localExternAddress ("") , _localExternPort (0) - , _audiortp (new sfl::AudioRtpFactory()) - ,_regPort (atoi (DEFAULT_SIP_PORT)) + , _regPort (atoi (DEFAULT_SIP_PORT)) , _clients (0) { // to get random number for RANDOM_PORT @@ -368,7 +367,7 @@ std::string SIPVoIPLink::get_useragent_name (void) void SIPVoIPLink::getEvent() { - // We have to register the external thread so it could access the pjsip framework + // We have to register the external thread so it could access the pjsip frameworks if (!pj_thread_is_registered()) pj_thread_register (NULL, desc, &thread); @@ -394,6 +393,8 @@ int SIPVoIPLink::sendRegister (AccountID id) pjsip_generic_string_hdr *h; pjsip_hdr hdr_list; + _debug("SIPVoIPLink::sendRegister()\n"); + account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (id)); if (account == NULL) { @@ -447,6 +448,7 @@ int SIPVoIPLink::sendRegister (AccountID id) if (account->isTlsEnabled()) { pj_status_t status; + _debug(" sendRegister: createTlsTransport\n"); status = createTlsTransportRetryOnFailure (id); if (status != PJ_SUCCESS) { @@ -454,27 +456,30 @@ int SIPVoIPLink::sendRegister (AccountID id) } } - // Launch a new UDP listener/transport, using the published address - if (account->isStunEnabled ()) { - pj_status_t status; + // Launch a new UDP listener/transport, using the published address + if (account->isStunEnabled ()) { + pj_status_t status; - status = createAlternateUdpTransport (id); + _debug(" sendRegister: createAlternateUdpTransport\n"); + status = createAlternateUdpTransport (id); - if (status != PJ_SUCCESS) { - _debug ("Failed to initialize UDP transport with an extern published address for account %s\n", id.c_str()); - } + if (status != PJ_SUCCESS) { + _debug ("Failed to initialize UDP transport with an extern published address for account %s\n", id.c_str()); } - else - { - status = createUDPServer (id); - if (status != PJ_SUCCESS) { - _debug ("Failed to initialize UDP transport with a local address for account %s\n. Try to use the local UDT transport", id.c_str()); - account->setAccountTransport (_localUDPTransport); - } + } + else + { + + status = createUDPServer (id); + if (status != PJ_SUCCESS) { + _debug ("Failed to initialize UDP transport with a local address for account %s\n. Try to use the local UDT transport", id.c_str()); + account->setAccountTransport (_localUDPTransport); } + } + _mutexSIP.enterMutex(); - + // Get the client registration information for this particular account regc = account->getRegistrationInfo(); account->setRegister (true); @@ -583,17 +588,17 @@ int SIPVoIPLink::sendRegister (AccountID id) _mutexSIP.leaveMutex(); return false; } + + pjsip_tpselector *tp; - // Set the appropriate transport - pjsip_tpselector *tp; - init_transport_selector (account->getAccountTransport (), &tp); - status = pjsip_regc_set_transport (regc, tp); - - if (status != PJ_SUCCESS) { - _debug ("UserAgent: Unable to set transport.\n"); - _mutexSIP.leaveMutex (); - return false; - } + init_transport_selector (account->getAccountTransport (), &tp); + status = pjsip_regc_set_transport (regc, tp); + + if (status != PJ_SUCCESS) { + _debug ("UserAgent: Unable to set transport.\n"); + _mutexSIP.leaveMutex (); + return false; + } // Send registration request status = pjsip_regc_send (regc, tdata); @@ -607,7 +612,7 @@ int SIPVoIPLink::sendRegister (AccountID id) _mutexSIP.leaveMutex(); account->setRegistrationInfo (regc); - + _debug("ok\n"); return true; } @@ -682,7 +687,7 @@ SIPVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl) try { _debug ("Creating new rtp session in newOutgoingCall\n"); - _audiortp->initAudioRtpSession (call); + call->getAudioRtp()->initAudioRtpSession (call); } catch (...) { _debug ("Failed to create rtp thread from newOutGoingCall\n"); } @@ -735,7 +740,7 @@ SIPVoIPLink::answer (const CallID& id) local_sdp = call->getLocalSDP(); try { - _audiortp->initAudioRtpSession (call); + call->getAudioRtp()->initAudioRtpSession (call); } catch (...) { _debug ("Failed to create rtp thread from answer\n"); } @@ -770,7 +775,7 @@ SIPVoIPLink::answer (const CallID& id) _debug ("SIPVoIPLink::answer: fail terminate call %s \n",call->getCallId().c_str()); terminateOneCall (call->getCallId()); removeCall (call->getCallId()); - _audiortp->stop (); + call->getAudioRtp()->stop (); return false; } } @@ -813,7 +818,7 @@ SIPVoIPLink::hangup (const CallID& id) // Release RTP thread if (Manager::instance().isCurrentCall (id)) { _debug ("* SIP Info: Stopping AudioRTP for hangup\n"); - _audiortp->stop(); + call->getAudioRtp()->stop(); } terminateOneCall (id); @@ -856,7 +861,7 @@ SIPVoIPLink::peerHungup (const CallID& id) // Release RTP thread if (Manager::instance().isCurrentCall (id)) { _debug ("* SIP Info: Stopping AudioRTP for hangup\n"); - _audiortp->stop(); + call->getAudioRtp()->stop(); } terminateOneCall (id); @@ -906,7 +911,7 @@ SIPVoIPLink::onhold (const CallID& id) _debug ("* SIP Info: Stopping AudioRTP for onhold action\n"); - _audiortp->stop(); + call->getAudioRtp()->stop(); /* Create re-INVITE with new offer */ status = inv_session_reinvite (call, "sendonly"); @@ -977,7 +982,7 @@ SIPVoIPLink::offhold (const CallID& id) } try { - _audiortp->initAudioRtpSession (call); + call->getAudioRtp()->initAudioRtpSession (call); } catch (...) { _debug ("! SIP Failure: Unable to create RTP Session (%s:%d)\n", __FILE__, __LINE__); } @@ -1074,9 +1079,9 @@ SIPVoIPLink::transfer (const CallID& id, const std::string& to) return true; } -bool SIPVoIPLink::transferStep2() +bool SIPVoIPLink::transferStep2(SIPCall* call) { - _audiortp->stop(); + call->getAudioRtp()->stop(); return true; } @@ -1119,27 +1124,6 @@ SIPVoIPLink::refuse (const CallID& id) return true; } -void -SIPVoIPLink::setRecording (const CallID& id) -{ - SIPCall* call = getSIPCall (id); - - if (call) - call->setRecording(); -} - -bool -SIPVoIPLink::isRecording (const CallID& id) -{ - SIPCall* call = getSIPCall (id); - _debug ("call->isRecording() %i \n",call->isRecording()); - - if (call) - return call->isRecording(); - else - return false; -} - std::string SIPVoIPLink::getCurrentCodecName() @@ -1244,7 +1228,6 @@ SIPVoIPLink::SIPStartCall (SIPCall* call, const std::string& subject UNUSED) pjsip_inv_session *inv; pjsip_dialog *dialog; pjsip_tx_data *tdata; - pjsip_transport *transport; AccountID id; @@ -1343,6 +1326,7 @@ SIPVoIPLink::SIPStartCall (SIPCall* call, const std::string& subject UNUSED) status = pjsip_inv_send_msg (inv, tdata); if (status != PJ_SUCCESS) { + _debug(" SIPStartCall: failed to send invite\n"); return false; } @@ -1358,7 +1342,7 @@ SIPVoIPLink::SIPCallServerFailure (SIPCall *call) Manager::instance().callFailure (id); terminateOneCall (id); removeCall (id); - _audiortp->stop(); + call->getAudioRtp()->stop(); } } @@ -1374,7 +1358,7 @@ SIPVoIPLink::SIPCallClosed (SIPCall *call) if (Manager::instance().isCurrentCall (id)) { call->setAudioStart (false); _debug ("* SIP Info: Stopping AudioRTP when closing\n"); - _audiortp->stop(); + call->getAudioRtp()->stop(); } _debug ("After close RTP\n"); @@ -1474,7 +1458,7 @@ bool SIPVoIPLink::new_ip_to_ip_call (const CallID& id, const std::string& to) call->getLocalSDP()->create_initial_offer(); try { - _audiortp->initAudioRtpSession (call); + call->getAudioRtp()->initAudioRtpSession (call); } catch (...) { _debug ("! SIP Failure: Unable to create RTP Session in SIPVoIPLink::new_ip_to_ip_call (%s:%d)\n", __FILE__, __LINE__); } @@ -1716,7 +1700,7 @@ bool SIPVoIPLink::pjsip_init() account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (AccountNULL)); if (account == NULL) { - _debug ("Account is null"); + _debug ("Account is null in pjsip init\n"); } else { directIpCallsTlsEnabled = account->isTlsEnabled(); } @@ -1863,7 +1847,7 @@ pj_status_t SIPVoIPLink::stunServerResolve (AccountID id) account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (id)); if (account == NULL) { - _debug ("stunServerResolve: Account is null. Returning"); + _debug ("stunServerResolve: Account is null. Returning\n"); return !PJ_SUCCESS; } // Get the STUN server name and port @@ -1909,42 +1893,52 @@ int SIPVoIPLink::createUDPServer (AccountID id) pj_sockaddr_in bound_addr; pjsip_host_port a_name; char tmpIP[32]; - pjsip_transport *transport; + pjsip_transport *transport; - /* - * Retrieve the account information - */ - SIPAccount * account = NULL; - account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (id)); - // Set information to the local address and port - if (account == NULL) { - // We are trying to initialize a UDP transport available for all local accounts and direct IP calls - _debug ("Account is null."); - _localExternAddress = _localIPAddress; - _localExternPort = _localPort; - } - else - { - _localExternAddress = account->getSessionAddress (); - _localExternPort = account->getSessionPort (); - } + /* + * Retrieve the account information + */ + SIPAccount * account = NULL; + account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (id)); + // Set information to the local address and port + if (account == NULL) { + // We are trying to initialize a UDP transport available for all local accounts and direct IP calls + _debug ("Account is null in createUDPServer.\n"); + _localExternAddress = _localIPAddress; + _localExternPort = _localPort; + } + else + { + _localExternAddress = account->getSessionAddress (); + _localExternPort = account->getSessionPort (); + } // Init bound address to ANY pj_memset (&bound_addr, 0, sizeof (bound_addr)); - + bound_addr.sin_addr.s_addr = pj_htonl (PJ_INADDR_ANY); bound_addr.sin_port = pj_htons ( (pj_uint16_t) _localPort); bound_addr.sin_family = PJ_AF_INET; pj_bzero (bound_addr.sin_zero, sizeof (bound_addr.sin_zero)); - + // Create UDP-Server (default port: 5060) strcpy (tmpIP, _localExternAddress.data()); pj_strdup2 (_pool, &a_name.host, tmpIP); a_name.port = (pj_uint16_t) _localExternPort; - + status = pjsip_udp_transport_start (_endpt, &bound_addr, &a_name, 1, &transport); + + + // Get the transport manager associated with + // this endpoint + pjsip_tpmgr * tpmgr = NULL; + + tpmgr = pjsip_endpt_get_tpmgr (_endpt); + + _debug("number of transport: %i\n", pjsip_tpmgr_get_transport_count(tpmgr)); + pjsip_tpmgr_dump_transports(tpmgr); if (status != PJ_SUCCESS) { _debug ("UserAgent: (%d) Unable to start UDP transport!\n", status); @@ -1965,11 +1959,13 @@ int SIPVoIPLink::createUDPServer (AccountID id) return PJ_SUCCESS; } -std::string SIPVoIPLink::findLocalAddressFromUri (const std::string& uri, pjsip_transport *transport) +std::string SIPVoIPLink::findLocalAddressFromUri(const std::string& uri, pjsip_transport *transport) { pj_str_t localAddress; pjsip_transport_type_e transportType; - pjsip_tpselector *tp_sel; + pjsip_tpselector *tp_sel; + + _debug("SIPVoIPLink::findLocalAddressFromUri\n"); // Find the transport that must be used with the given uri pj_str_t tmp; @@ -2010,7 +2006,7 @@ std::string SIPVoIPLink::findLocalAddressFromUri (const std::string& uri, pjsip_ // this endpoint pjsip_tpmgr * tpmgr = NULL; - tpmgr = pjsip_endpt_get_tpmgr (_endpt); + tpmgr = pjsip_endpt_get_tpmgr (_endpt); if (tpmgr == NULL) { _debug ("Unexpected: Cannot get tpmgr from endpoint.\n"); @@ -2023,21 +2019,23 @@ std::string SIPVoIPLink::findLocalAddressFromUri (const std::string& uri, pjsip_ pj_status_t status; + /* Init the transport selector */ //_debug ("Transport ID: %s\n", transport->obj_name); status = init_transport_selector (transport, &tp_sel); - if (status == PJ_SUCCESS) - status = pjsip_tpmgr_find_local_addr (tpmgr, _pool, transportType, tp_sel, &localAddress, &port); - else - status = pjsip_tpmgr_find_local_addr (tpmgr, _pool, transportType, NULL, &localAddress, &port); + + if (status == PJ_SUCCESS) + status = pjsip_tpmgr_find_local_addr (tpmgr, _pool, transportType, tp_sel, &localAddress, &port); + else + status = pjsip_tpmgr_find_local_addr (tpmgr, _pool, transportType, NULL, &localAddress, &port); if (status != PJ_SUCCESS) { _debug ("Failed to find local address from transport\n"); return machineName; } - _debug ("Local ADdress From URI: %s\n", localAddress.ptr); + // _debug ("Local ADdress From URI: %s\n", localAddress.ptr); return std::string (localAddress.ptr, localAddress.slen); } @@ -2111,17 +2109,17 @@ int SIPVoIPLink::findLocalPortFromUri (const std::string& uri, pjsip_transport * // Find the local address (and port) based on the registered // transports and the transport type - - /* Init the transport selector */ - _debug ("Transport ID: %s\n", transport->obj_name); + + /* Init the transport selector */ + _debug ("Transport ID: %s\n", transport->obj_name); pj_status_t status; - status = init_transport_selector (transport, &tp_sel); + status = init_transport_selector (transport, &tp_sel); - if (status == PJ_SUCCESS) - status = pjsip_tpmgr_find_local_addr (tpmgr, _pool, transportType, tp_sel, &localAddress, &port); - else - status = pjsip_tpmgr_find_local_addr (tpmgr, _pool, transportType, NULL, &localAddress, &port); + if (status == PJ_SUCCESS) + status = pjsip_tpmgr_find_local_addr (tpmgr, _pool, transportType, tp_sel, &localAddress, &port); + else + status = pjsip_tpmgr_find_local_addr (tpmgr, _pool, transportType, NULL, &localAddress, &port); if (status != PJ_SUCCESS) { _debug ("Failed to find local address from transport\n"); @@ -2149,7 +2147,7 @@ pj_status_t SIPVoIPLink::createTlsTransportRetryOnFailure (AccountID id) account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (id)); if (account == NULL) { - _debug ("createTlsTransportRetryOnFailure: Account is null. Returning"); + _debug ("createTlsTransportRetryOnFailure: Account is null. Returning\n"); return !PJ_SUCCESS; } @@ -2187,7 +2185,7 @@ pj_status_t SIPVoIPLink::createAlternateUdpTransport (AccountID id) account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (id)); if (account == NULL) { - _debug ("Account is null. Returning"); + _debug ("Account is null. Returning\n"); return !PJ_SUCCESS; } @@ -2272,7 +2270,7 @@ pj_status_t SIPVoIPLink::createTlsTransport (AccountID id) account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (id)); if (account == NULL) { - _debug ("Account is null. Returning"); + _debug ("Account is null. Returning\n"); return !PJ_SUCCESS; } @@ -2467,13 +2465,13 @@ void set_voicemail_info (AccountID account, pjsip_msg_body *body) void SIPVoIPLink::handle_reinvite (SIPCall *call) { // Close the previous RTP session - _audiortp->stop (); + call->getAudioRtp()->stop (); call->setAudioStart (false); _debug ("Create new rtp session from handle_reinvite : %s:%i\n", call->getLocalIp().c_str(), call->getLocalAudioPort()); try { - _audiortp->initAudioRtpSession (call); + call->getAudioRtp()->initAudioRtpSession (call); } catch (...) { _debug ("! SIP Failure: Unable to create RTP Session (%s:%d)\n", __FILE__, __LINE__); } @@ -2495,6 +2493,11 @@ void call_on_state_changed (pjsip_inv_session *inv, pjsip_event *e) _debug ("Call is NULL in call_on_state_changed"); return; } + else + { + // _debug(" call_on_state_changed: call id %s\n", call->getCallId().c_str()); + // _debug(" call_on_state_changed: call state %s\n", invitationStateMap[call->getInvSession()->state]); + } //Retrieve the body message rdata = e->body.tsx_state.src.rdata; @@ -2524,6 +2527,7 @@ void call_on_state_changed (pjsip_inv_session *inv, pjsip_event *e) pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE; switch (call->getInvSession()->state) { + // switch (inv->state) { case PJSIP_INV_STATE_NULL: @@ -2702,6 +2706,10 @@ void call_on_media_update (pjsip_inv_session *inv, pj_status_t status) return; } + if(!inv->neg) + { + return; + } // Get the new sdp, result of the negotiation pjmedia_sdp_neg_get_active_local (inv->neg, &local_sdp); @@ -2720,9 +2728,9 @@ void call_on_media_update (pjsip_inv_session *inv, pj_status_t status) try { call->setAudioStart (true); - link->getAudioRtp()->start(); - } catch (exception& rtpException) { - _debug ("%s\n", rtpException.what()); + call->getAudioRtp()->start(); + } catch(exception& rtpException) { + _debug("%s\n", rtpException.what()); } } @@ -3377,13 +3385,21 @@ void xfer_func_cb (pjsip_evsub *sub, pjsip_event *event) status_line.reason = *pjsip_get_status_text (500); } + // Get current call + SIPCall *call = dynamic_cast<SIPCall *> (link->getCall (Manager::instance().getCurrentCallId())); + + if (!call) { + _debug ("UserAgent: Call doesn't exit!\n"); + return; + } + if (event->body.rx_msg.rdata->msg_info.msg_buf != NULL) { request = event->body.rx_msg.rdata->msg_info.msg_buf; if ( (int) request.find (noresource) != -1) { _debug ("UserAgent: NORESOURCE for transfer!\n"); - link->transferStep2(); + link->transferStep2(call); pjsip_evsub_terminate (sub, PJ_TRUE); Manager::instance().transferFailed(); @@ -3392,7 +3408,7 @@ void xfer_func_cb (pjsip_evsub *sub, pjsip_event *event) if ( (int) request.find (ringing) != -1) { _debug ("UserAgent: transfered call RINGING!\n"); - link->transferStep2(); + link->transferStep2(call); pjsip_evsub_terminate (sub, PJ_TRUE); Manager::instance().transferSucceded(); @@ -3401,15 +3417,6 @@ void xfer_func_cb (pjsip_evsub *sub, pjsip_event *event) } - // Get current call - SIPCall *call = dynamic_cast<SIPCall *> (link->getCall (Manager::instance().getCurrentCallId())); - - if (!call) { - _debug ("UserAgent: Call doesn't exit!\n"); - return; - } - - /* Notify application */ is_last = (pjsip_evsub_get_state (sub) ==PJSIP_EVSUB_STATE_TERMINATED); @@ -3431,7 +3438,7 @@ void xfer_func_cb (pjsip_evsub *sub, pjsip_event *event) _debug ("UserAgent: Fail to send end session msg!\n"); } - link->transferStep2(); + link->transferStep2(call); cont = PJ_FALSE; } @@ -3578,8 +3585,8 @@ bool setCallAudioLocal (SIPCall* call, std::string localIP) //} } + _debug (" Setting local ip address: %s\n", localIP.c_str()); _debug (" Setting local audio port to: %d\n", callLocalAudioPort); - _debug (" Setting local audio port (external) to: %d\n", callLocalExternAudioPort); // Set local audio port for SIPCall(id) @@ -3644,7 +3651,7 @@ std::vector<std::string> SIPVoIPLink::getAllIpInterface (void) int i; - for (i = 0; i < addrCnt; i++) { + for (i = 0; i < (int)addrCnt; i++) { char tmpAddr[PJ_INET_ADDRSTRLEN]; pj_sockaddr_print (&addrList[i], tmpAddr, sizeof (tmpAddr), 0); ifaceList.push_back (std::string (tmpAddr)); diff --git a/sflphone-common/src/sip/sipvoiplink.h b/sflphone-common/src/sip/sipvoiplink.h index 634a8a4f1aa630289bb7e74f90a4f2dc2d904477..f2c49302b80f98d85ac29795e71f7cdd7064977e 100644 --- a/sflphone-common/src/sip/sipvoiplink.h +++ b/sflphone-common/src/sip/sipvoiplink.h @@ -26,7 +26,6 @@ #include "voiplink.h" #include "hooks/urlhook.h" -#include "audio/audiortp/AudioRtpFactory.h" ////////////////////////////// /* PJSIP imports */ @@ -39,11 +38,6 @@ class EventThread; class SIPCall; -class AudioRtp; - -namespace sfl { - class AudioRtpFactory; -} #define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2 #define RANDOM_SIP_PORT rand() % 64000 + 1024 @@ -168,7 +162,7 @@ class SIPVoIPLink : public VoIPLink bool transfer(const CallID& id, const std::string& to); /** Handle the incoming refer msg, not finished yet */ - bool transferStep2(); + bool transferStep2(SIPCall* call); /** * Refuse the call @@ -252,9 +246,6 @@ class SIPVoIPLink : public VoIPLink /** when we init the listener, how many times we try to bind a port? */ int _nbTryListenAddr; - /** Returns a pointer to the AudioRtp object */ - inline sfl::AudioRtpFactory * getAudioRtp(void) { return _audiortp; } - /** Increment the number of SIP account connected to this link */ void incrementClients (void) { _clients++; } @@ -388,9 +379,6 @@ class SIPVoIPLink : public VoIPLink /** Local Extern Port is the port seen by peers for SIP listener */ unsigned int _localExternPort; - - /** Starting sound */ - sfl::AudioRtpFactory * _audiortp; /** For registration use only */ int _regPort; diff --git a/sflphone-common/src/voiplink.h b/sflphone-common/src/voiplink.h index b78646b41f1c597ddd35f5bedcacc130c4a97748..09ea20b3c2708f63a6b0a38053a214755843c5fa 100644 --- a/sflphone-common/src/voiplink.h +++ b/sflphone-common/src/voiplink.h @@ -164,13 +164,13 @@ class VoIPLink { * Set Recording * @param id The call identifier */ - virtual void setRecording(const CallID& id) = 0; + // virtual void setRecording(const CallID& id) = 0; /** * Return recording state * @param id The call identifier */ - virtual bool isRecording(const CallID& id) = 0; + // virtual bool isRecording(const CallID& id) = 0; /** * Return the codec protocol used for this call diff --git a/sflphone-common/test/Makefile.am b/sflphone-common/test/Makefile.am index 6700e93d458928c162c88582d355673500aa89ba..87264309aa0f6008c2e6a5704122de0593a5d097 100644 --- a/sflphone-common/test/Makefile.am +++ b/sflphone-common/test/Makefile.am @@ -1,6 +1,7 @@ include ../globals.mak -noinst_PROGRAMS = numbercleanerTester pluginmanagerTester hookmanagerTester audiolayerTester historyTester #rtpTester + +noinst_PROGRAMS = numbercleanerTester pluginmanagerTester hookmanagerTester audiolayerTester historyTester mainbufferTester #rtpTester OBJECT_FILES= \ ../src/sflphoned-managerimpl.o \ @@ -15,13 +16,15 @@ OBJECT_FILES= \ ../src/sip/sipaccount.o \ ../src/iax/libiaxlink_la-iaxaccount.o \ ../src/sflphoned-eventthread.o \ + ../src/sflphoned-conference.o \ ../src/plug-in/pluginmanager.o \ ../src/plug-in/audiorecorder/audiorecord.o \ ../src/audio/samplerateconverter.o \ ../src/sip/sdp.o \ ../src/sip/sdpmedia.o \ ../src/sflphoned-numbercleaner.o \ - ../src/history/historymanager.o + ../src/history/historymanager.o + ../ numbercleanerTester_SOURCES = \ numbercleanerTest.h \ @@ -102,12 +105,12 @@ audiolayerTester_LDADD = \ $(PJSIP_LIBS) \ $(OBJECT_FILES) -rtpTester_SOURCES = \ - rtpTest.h \ - rtpTest.cpp \ +historyTester_SOURCES = \ + historyTest.h \ + historyTest.cpp \ TestMain.cpp -rtpTester_LDADD = \ +historyTester_LDADD = \ ../src/libsflphone.la \ $(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) \ @ALSA_LIBS@ \ @@ -116,18 +119,19 @@ rtpTester_LDADD = \ @CCEXT2_LIBS@ \ @CCGNU2_LIBS@ \ @CCRTP_LIBS@ \ - @SAMPLERATE_LIBS@ \ @ZRTPCPP_LIBS@ \ @libssl_LIBS@ \ + @SAMPLERATE_LIBS@ \ $(PJSIP_LIBS) \ $(OBJECT_FILES) -historyTester_SOURCES = \ - historyTest.h \ - historyTest.cpp \ + +mainbufferTester_SOURCES = \ + mainbufferTest.h \ + mainbufferTest.cpp \ TestMain.cpp -historyTester_LDADD = \ +mainbufferTester_LDADD = \ ../src/libsflphone.la \ $(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) \ @ALSA_LIBS@ \ @@ -141,4 +145,3 @@ historyTester_LDADD = \ @SAMPLERATE_LIBS@ \ $(PJSIP_LIBS) \ $(OBJECT_FILES) - diff --git a/sflphone-common/test/mainbufferTest.cpp b/sflphone-common/test/mainbufferTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3cdfa6515db33982fa4561f692d40291c234e74 --- /dev/null +++ b/sflphone-common/test/mainbufferTest.cpp @@ -0,0 +1,1772 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdio.h> +#include <sstream> +#include <ccrtp/rtp.h> +#include <assert.h> +#include <string> +#include <cstring> +#include <math.h> +#include <dlfcn.h> +#include <iostream> +#include <sstream> + + +#include "mainbufferTest.h" + +#include <unistd.h> + + +using std::cout; +using std::endl; + + +void MainBufferTest::setUp() +{ + + +} + + +void MainBufferTest::tearDown() +{ + +} + + +void MainBufferTest::testRingBufferCreation() +{ + _debug("MainBufferTest::testRingBufferCreation()\n"); + + CallID test_id = "1234"; + CallID null_id = "null id"; + + RingBuffer* test_ring_buffer; + RingBufferMap::iterator iter; + + // test mainbuffer ringbuffer map size + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 0); + test_ring_buffer = _mainbuffer.createRingBuffer(test_id); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 1); + + // test _mainbuffer.getRingBuffer method + CPPUNIT_ASSERT(test_ring_buffer != NULL); + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(null_id) == NULL); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 1); + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(test_id) == test_ring_buffer); + + // test _mainbuffer _ringBufferMap + iter = _mainbuffer._ringBufferMap.find(null_id); + CPPUNIT_ASSERT(iter == _mainbuffer._ringBufferMap.end()); + iter = _mainbuffer._ringBufferMap.find(test_id); + CPPUNIT_ASSERT(iter->first == test_id); + CPPUNIT_ASSERT(iter->second == test_ring_buffer); + CPPUNIT_ASSERT(iter->second == _mainbuffer.getRingBuffer(test_id)); + + // test creating twice a buffer (should not create it) + _mainbuffer.createRingBuffer(test_id); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 1); + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(test_id) == test_ring_buffer); + + // test remove ring buffer + CPPUNIT_ASSERT(_mainbuffer.removeRingBuffer(null_id) == true); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 1); + CPPUNIT_ASSERT(_mainbuffer.removeRingBuffer(test_id) == true); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 0); + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(test_id) == NULL); + + iter = _mainbuffer._ringBufferMap.find(test_id); + CPPUNIT_ASSERT(iter == _mainbuffer._ringBufferMap.end()); + +} + + +void MainBufferTest::testRingBufferReadPointer() +{ + _debug("MainBufferTest::testRingBufferReadPointer()\n"); + + CallID call_id = "call id"; + CallID read_id = "read id"; + CallID null_id = "null id"; + CallID other_id = "other id"; + + RingBuffer* test_ring_buffer; + + // test ring buffer read pointers (one per participant) + test_ring_buffer = _mainbuffer.createRingBuffer(call_id); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 0); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(read_id) == (int)NULL); + + // create a read pointer + test_ring_buffer->createReadPointer(read_id); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 1); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(null_id) == (int)NULL); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(read_id) == 0); + + // store read pointer + test_ring_buffer->storeReadPointer(4, read_id); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 1); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(read_id) == 4); + + // recreate the same read pointer (should not add a pointer neither chage its value) + test_ring_buffer->createReadPointer(read_id); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 1); + test_ring_buffer->storeReadPointer(8, read_id); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(read_id) == 8); + + // test getSmallest read pointer (to get the length available to put data in the buffer) + test_ring_buffer->createReadPointer(other_id); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 2); + test_ring_buffer->storeReadPointer(4, other_id); + CPPUNIT_ASSERT(test_ring_buffer->getSmallestReadPointer() == 4); + + // remove read pointers + test_ring_buffer->removeReadPointer(other_id); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 1); + test_ring_buffer->removeReadPointer(read_id); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 0); +} + + +void MainBufferTest::testCallIDSet() +{ + _debug("MainBufferTest::testCallIDSet()\n"); + + CallID test_id = "set id"; + CallID false_id = "false set id"; + // CallIDSet* callid_set = 0; + + CallIDMap::iterator iter_map; + CallIDSet::iterator iter_set; + + CallID call_id_1 = "call id 1"; + CallID call_id_2 = "call id 2"; + + // test initial settings + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 0); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 0); + iter_map = _mainbuffer._callIDMap.find(test_id); + CPPUNIT_ASSERT(iter_map ==_mainbuffer._callIDMap.end()); + + // test callidset creation + CPPUNIT_ASSERT(_mainbuffer.createCallIDSet(test_id) == true); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 1); + iter_map = _mainbuffer._callIDMap.find(test_id); + CPPUNIT_ASSERT(iter_map->first == test_id); + CPPUNIT_ASSERT(iter_map->second == _mainbuffer.getCallIDSet(test_id)); + + CPPUNIT_ASSERT(_mainbuffer.getCallIDSet(false_id) == NULL); + CPPUNIT_ASSERT(_mainbuffer.getCallIDSet(test_id) != NULL); + + + // Test callIDSet add call_ids + _mainbuffer.addCallIDtoSet(test_id, call_id_1); + iter_map = _mainbuffer._callIDMap.find(test_id); + CPPUNIT_ASSERT(iter_map->second->size() == 1); + iter_set = iter_map->second->find(call_id_1); + CPPUNIT_ASSERT(*iter_set == call_id_1); + + // test add second call id to set + _mainbuffer.addCallIDtoSet(test_id, call_id_2); + iter_map = _mainbuffer._callIDMap.find(test_id); + CPPUNIT_ASSERT(iter_map->second->size() == 2); + iter_set = iter_map->second->find(call_id_2); + CPPUNIT_ASSERT(*iter_set == call_id_2); + + // test add a call id twice + _mainbuffer.addCallIDtoSet(test_id, call_id_2); + iter_map = _mainbuffer._callIDMap.find(test_id); + CPPUNIT_ASSERT(iter_map->second->size() == 2); + iter_set = iter_map->second->find(call_id_2); + CPPUNIT_ASSERT(*iter_set == call_id_2); + + // test remove a call id + _mainbuffer.removeCallIDfromSet(test_id, call_id_2); + iter_map = _mainbuffer._callIDMap.find(test_id); + CPPUNIT_ASSERT(iter_map->second->size() == 1); + iter_set = iter_map->second->find(call_id_1); + CPPUNIT_ASSERT(*iter_set == call_id_1); + iter_set = iter_map->second->find(call_id_2); + CPPUNIT_ASSERT(iter_set == iter_map->second->end()); + + // test remove a call id twice + _mainbuffer.removeCallIDfromSet(test_id, call_id_2); + iter_map = _mainbuffer._callIDMap.find(test_id); + CPPUNIT_ASSERT(iter_map->second->size() == 1); + iter_set = iter_map->second->find(call_id_1); + CPPUNIT_ASSERT(*iter_set == call_id_1); + iter_set = iter_map->second->find(call_id_2); + CPPUNIT_ASSERT(iter_set == iter_map->second->end()); + + // Test removeCallIDSet + CPPUNIT_ASSERT(_mainbuffer.removeCallIDSet(false_id) == false); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 1); + CPPUNIT_ASSERT(_mainbuffer.removeCallIDSet(test_id) == true); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 0); + + iter_map = _mainbuffer._callIDMap.find(test_id); + CPPUNIT_ASSERT(iter_map ==_mainbuffer._callIDMap.end()); + + +} + + +void MainBufferTest::testRingBufferInt() +{ + + _debug("MainBufferTest::testRingbufferInt()\n"); + + // CallID test_id = "test_int"; + + int testint1 = 12; + int testint2 = 13; + int init_put_size; + + + // test with default ring buffer + RingBuffer* test_ring_buffer = _mainbuffer.createRingBuffer(default_id); + + // initial state + init_put_size = test_ring_buffer->AvailForPut(); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 0); + + // add some data + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint1, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - (int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 0); + + // add some other data + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint2, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - 2*(int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 0); + + int testget = (int)NULL; + + // get some data (without any read pointers) + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen() == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->Get(&testget, sizeof(int)) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen() == 2*sizeof(int)); + CPPUNIT_ASSERT(testget == (int)NULL); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - 2*(int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 0); + + // get some data (with a read pointer) + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 0); + test_ring_buffer->createReadPointer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 1); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == 0); + CPPUNIT_ASSERT(test_ring_buffer->getLen() == 0); + + // add some data + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint1, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - (int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 2*sizeof(int)); + + // add some other data + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint2, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - 2*(int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 2*sizeof(int)); + + CPPUNIT_ASSERT(test_ring_buffer->Get(&testget, sizeof(int), 100, default_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen() == sizeof(int)); + CPPUNIT_ASSERT(testget == testint1); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - (int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 3*sizeof(int)); + + CPPUNIT_ASSERT(test_ring_buffer->Get(&testget, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(testget == testint2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == 0); + CPPUNIT_ASSERT(test_ring_buffer->getLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_size); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 4*sizeof(int)); + + + // test flush data + init_put_size = test_ring_buffer->AvailForPut(); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint1, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - (int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen() == sizeof(int)); + + + test_ring_buffer->flush(); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_size); + CPPUNIT_ASSERT(test_ring_buffer->getLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == 0); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 5*sizeof(int)); + + // test flush data + init_put_size = test_ring_buffer->AvailForPut(); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint1, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - (int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 5*sizeof(int)); + + test_ring_buffer->Discard(sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_size); + CPPUNIT_ASSERT(test_ring_buffer->getLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == 0); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 6*sizeof(int)); + + +} + + +void MainBufferTest::testRingBufferNonDefaultID() +{ + + _debug("MainBufferTest::testRingBufferNonDefaultID()\n"); + + CallID test_id = "test_int"; + + int testint1 = 12; + int testint2 = 13; + int init_put_size; + + + // test putData, getData with arbitrary read pointer id + RingBuffer* test_ring_buffer = _mainbuffer.createRingBuffer(default_id); + test_ring_buffer->createReadPointer(test_id); + + init_put_size = test_ring_buffer->AvailForPut(); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(default_id) == 0); + + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint1, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - (int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(default_id) == 0); + + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint2, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - 2*(int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(default_id) == 0); + + int testget; + + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id) == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_id) == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->Get(&testget, sizeof(int), 100, test_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_id) == sizeof(int)); + CPPUNIT_ASSERT(testget == testint1); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - (int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == sizeof(int)); + + CPPUNIT_ASSERT(test_ring_buffer->Get(&testget, sizeof(int), 100, test_id) == sizeof(int)); + CPPUNIT_ASSERT(testget == testint2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_size); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 2*sizeof(int)); + + + // test flush data + init_put_size = test_ring_buffer->AvailForPut(); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint1, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - (int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_id) == sizeof(int)); + + + test_ring_buffer->flush(test_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_size); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 3*sizeof(int)); + + // test flush data + init_put_size = test_ring_buffer->AvailForPut(); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint1, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (init_put_size - (int)sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 3*sizeof(int)); + + test_ring_buffer->Discard(sizeof(int), test_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_size); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 4*sizeof(int)); + + test_ring_buffer->removeReadPointer(test_id); + +} + + +void MainBufferTest::testRingBufferFloat() +{ + + _debug("MainBufferTest::testRingBufferFloat()\n"); + + float testfloat1 = 12.5; + float testfloat2 = 13.4; + + RingBuffer* test_ring_buffer = _mainbuffer.createRingBuffer(default_id); + test_ring_buffer->createReadPointer(default_id); + + + CPPUNIT_ASSERT(test_ring_buffer->Put(&testfloat1, sizeof(float)) == sizeof(float)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(float)); + + CPPUNIT_ASSERT(test_ring_buffer->Put(&testfloat2, sizeof(float)) == sizeof(float)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 2*sizeof(float)); + + float testget; + + CPPUNIT_ASSERT(test_ring_buffer->Get(&testget, sizeof(float)) == sizeof(float)); + CPPUNIT_ASSERT(test_ring_buffer->getLen() == sizeof(float)); + CPPUNIT_ASSERT(testget == testfloat1); + + CPPUNIT_ASSERT(test_ring_buffer->Get(&testget, sizeof(float)) == sizeof(float)); + CPPUNIT_ASSERT(testget == testfloat2); + CPPUNIT_ASSERT(test_ring_buffer->getLen() == 0); + + CPPUNIT_ASSERT(test_ring_buffer->Put(&testfloat1, sizeof(float)) == sizeof(float)); + test_ring_buffer->flush(); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + +} + + +void MainBufferTest::testTwoPointer() +{ + + _debug("MainBufferTest::testTwoPointer()\n"); + + + RingBuffer* input_buffer = _mainbuffer.createRingBuffer(default_id); + input_buffer->createReadPointer(default_id); + RingBuffer* output_buffer = _mainbuffer.getRingBuffer(default_id); + + int test_input = 12; + int test_output; + + CPPUNIT_ASSERT(input_buffer->Put(&test_input, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(output_buffer->Get(&test_output, sizeof(float)) == sizeof(float)); + CPPUNIT_ASSERT(test_input == test_output); + +} + +void MainBufferTest::testBindUnbindBuffer() +{ + + _debug("MainBufferTest::testBindUnbindBuffer()\n"); + + CallID test_id1 = "bind unbind 1"; + CallID test_id2 = "bind unbind 2"; + + RingBufferMap::iterator iter_buffer; + CallIDMap::iterator iter_idset; + CallIDSet::iterator iter_id; + + ReadPointer::iterator iter_readpointer; + + RingBuffer* ringbuffer; + + // test initial state with no ring brffer created + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 0); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 0); + + iter_buffer = _mainbuffer._ringBufferMap.find(default_id); + CPPUNIT_ASSERT(iter_buffer == _mainbuffer._ringBufferMap.end()); + iter_idset = _mainbuffer._callIDMap.find(default_id); + CPPUNIT_ASSERT(iter_idset == _mainbuffer._callIDMap.end()); + + // bind test_id1 with default_id (both buffer not already created) + _mainbuffer.bindCallID(test_id1); + + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 2); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 2); + + iter_buffer = _mainbuffer._ringBufferMap.find(default_id); + CPPUNIT_ASSERT(iter_buffer->first == default_id); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(default_id)); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id1); + CPPUNIT_ASSERT(iter_buffer->first == test_id1); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(test_id1)); + + iter_idset = _mainbuffer._callIDMap.find(default_id); + CPPUNIT_ASSERT(iter_idset->second->size() == 1); + iter_id = iter_idset->second->find(test_id1); + CPPUNIT_ASSERT(*iter_id == test_id1); + + iter_idset = _mainbuffer._callIDMap.find(test_id1); + CPPUNIT_ASSERT(iter_idset->second->size() == 1); + iter_id = iter_idset->second->find(default_id); + CPPUNIT_ASSERT(*iter_id == default_id); + + ringbuffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 1); + iter_readpointer = ringbuffer->_readpointer.find(test_id1); + CPPUNIT_ASSERT(iter_readpointer->first == test_id1); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + + ringbuffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 1); + iter_readpointer = ringbuffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + + + // unbind test_id1 with default_id + _mainbuffer.unBindCallID(test_id1); + + _debug("%i\n", _mainbuffer._ringBufferMap.size()); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 0); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 0); + + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(default_id) == NULL); + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(test_id1) == NULL); + + + // bind test_id2 with default_id (default_id already created) + // calling it twice not supposed to break anything + _mainbuffer.bindCallID(test_id1, default_id); + _mainbuffer.bindCallID(test_id1, default_id); + + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 2); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 2); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id2); + CPPUNIT_ASSERT(iter_buffer == _mainbuffer._ringBufferMap.end()); + iter_idset = _mainbuffer._callIDMap.find(test_id2); + CPPUNIT_ASSERT(iter_idset == _mainbuffer._callIDMap.end()); + + _mainbuffer.bindCallID(test_id2, default_id); + _mainbuffer.bindCallID(test_id2, default_id); + + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 3); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 3); + + iter_buffer = _mainbuffer._ringBufferMap.find(default_id); + CPPUNIT_ASSERT(iter_buffer->first == default_id); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(default_id)); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id1); + CPPUNIT_ASSERT(iter_buffer->first == test_id1); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(test_id1)); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id2); + CPPUNIT_ASSERT(iter_buffer->first == test_id2); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(test_id2)); + + iter_idset = _mainbuffer._callIDMap.find(default_id); + CPPUNIT_ASSERT(iter_idset->second->size() == 2); + iter_id = iter_idset->second->find(test_id1); + CPPUNIT_ASSERT(*iter_id == test_id1); + iter_id = iter_idset->second->find(test_id2); + CPPUNIT_ASSERT(*iter_id == test_id2); + + iter_idset = _mainbuffer._callIDMap.find(test_id1); + CPPUNIT_ASSERT(iter_idset->second->size() == 1); + iter_id = iter_idset->second->find(default_id); + CPPUNIT_ASSERT(*iter_id == default_id); + + iter_idset = _mainbuffer._callIDMap.find(test_id2); + CPPUNIT_ASSERT(iter_idset->second->size() == 1); + iter_id = iter_idset->second->find(default_id); + CPPUNIT_ASSERT(*iter_id == default_id); + + ringbuffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 2); + iter_readpointer = ringbuffer->_readpointer.find(test_id1); + CPPUNIT_ASSERT(iter_readpointer->first == test_id1); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = ringbuffer->_readpointer.find(test_id2); + CPPUNIT_ASSERT(iter_readpointer->first == test_id2); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + + ringbuffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 1); + iter_readpointer = ringbuffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + + ringbuffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 1); + iter_readpointer = ringbuffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + + // bind test_id1 with test_id2 (both testid1 and test_id2 already created) + // calling it twice not supposed to break anything + _mainbuffer.bindCallID(test_id1, test_id2); + _mainbuffer.bindCallID(test_id1, test_id2); + + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 3); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 3); + + iter_buffer = _mainbuffer._ringBufferMap.find(default_id); + CPPUNIT_ASSERT(iter_buffer->first == default_id); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(default_id)); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id1); + CPPUNIT_ASSERT(iter_buffer->first == test_id1); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(test_id1)); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id2); + CPPUNIT_ASSERT(iter_buffer->first == test_id2); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(test_id2)); + + iter_idset = _mainbuffer._callIDMap.find(default_id); + CPPUNIT_ASSERT(iter_idset->second->size() == 2); + iter_id = iter_idset->second->find(test_id1); + CPPUNIT_ASSERT(*iter_id == test_id1); + iter_id = iter_idset->second->find(test_id2); + CPPUNIT_ASSERT(*iter_id == test_id2); + + iter_idset = _mainbuffer._callIDMap.find(test_id1); + CPPUNIT_ASSERT(iter_idset->second->size() == 2); + iter_id = iter_idset->second->find(default_id); + CPPUNIT_ASSERT(*iter_id == default_id); + iter_id = iter_idset->second->find(test_id2); + CPPUNIT_ASSERT(*iter_id == test_id2); + + iter_idset = _mainbuffer._callIDMap.find(test_id2); + CPPUNIT_ASSERT(iter_idset->second->size() == 2); + iter_id = iter_idset->second->find(default_id); + CPPUNIT_ASSERT(*iter_id == default_id); + iter_id = iter_idset->second->find(test_id1); + CPPUNIT_ASSERT(*iter_id == test_id1); + + ringbuffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 2); + iter_readpointer = ringbuffer->_readpointer.find(test_id1); + CPPUNIT_ASSERT(iter_readpointer->first == test_id1); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = ringbuffer->_readpointer.find(test_id2); + CPPUNIT_ASSERT(iter_readpointer->first == test_id2); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + + ringbuffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 2); + iter_readpointer = ringbuffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = ringbuffer->_readpointer.find(test_id2); + CPPUNIT_ASSERT(iter_readpointer->first == test_id2); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + + ringbuffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 2); + iter_readpointer = ringbuffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = ringbuffer->_readpointer.find(test_id1); + CPPUNIT_ASSERT(iter_readpointer->first == test_id1); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + + // unbind test_id1 with test_id2 + // calling it twice not supposed to break anything + _mainbuffer.unBindCallID(test_id1, test_id2); + _mainbuffer.unBindCallID(test_id1, test_id2); + + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 3); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 3); + + iter_buffer = _mainbuffer._ringBufferMap.find(default_id); + CPPUNIT_ASSERT(iter_buffer->first == default_id); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(default_id)); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id1); + CPPUNIT_ASSERT(iter_buffer->first == test_id1); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(test_id1)); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id2); + CPPUNIT_ASSERT(iter_buffer->first == test_id2); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(test_id2)); + + iter_idset = _mainbuffer._callIDMap.find(default_id); + CPPUNIT_ASSERT(iter_idset->second->size() == 2); + iter_id = iter_idset->second->find(test_id1); + CPPUNIT_ASSERT(*iter_id == test_id1); + iter_id = iter_idset->second->find(test_id2); + CPPUNIT_ASSERT(*iter_id == test_id2); + + iter_idset = _mainbuffer._callIDMap.find(test_id1); + CPPUNIT_ASSERT(iter_idset->second->size() == 1); + iter_id = iter_idset->second->find(default_id); + CPPUNIT_ASSERT(*iter_id == default_id); + + iter_idset = _mainbuffer._callIDMap.find(test_id2); + CPPUNIT_ASSERT(iter_idset->second->size() == 1); + iter_id = iter_idset->second->find(default_id); + CPPUNIT_ASSERT(*iter_id == default_id); + + ringbuffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 2); + iter_readpointer = ringbuffer->_readpointer.find(test_id1); + CPPUNIT_ASSERT(iter_readpointer->first == test_id1); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = ringbuffer->_readpointer.find(test_id2); + CPPUNIT_ASSERT(iter_readpointer->first == test_id2); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + + ringbuffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 1); + iter_readpointer = ringbuffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + + ringbuffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 1); + iter_readpointer = ringbuffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + + + _debug("ok1\n"); + + // unbind test_id1 with test_id2 + // calling it twice not supposed to break anything + _mainbuffer.unBindCallID(default_id, test_id2); + _mainbuffer.unBindCallID(default_id, test_id2); + + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 2); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 2); + + iter_buffer = _mainbuffer._ringBufferMap.find(default_id); + CPPUNIT_ASSERT(iter_buffer->first == default_id); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(default_id)); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id1); + CPPUNIT_ASSERT(iter_buffer->first == test_id1); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(test_id1)); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id2); + CPPUNIT_ASSERT(iter_buffer == _mainbuffer._ringBufferMap.end()); + + iter_idset = _mainbuffer._callIDMap.find(default_id); + CPPUNIT_ASSERT(iter_idset->second->size() == 1); + iter_id = iter_idset->second->find(test_id1); + CPPUNIT_ASSERT(*iter_id == test_id1); + iter_id = iter_idset->second->find(test_id2); + CPPUNIT_ASSERT(iter_id == iter_idset->second->end()); + + iter_idset = _mainbuffer._callIDMap.find(test_id1); + CPPUNIT_ASSERT(iter_idset->second->size() == 1); + iter_id = iter_idset->second->find(default_id); + CPPUNIT_ASSERT(*iter_id == default_id); + + iter_idset = _mainbuffer._callIDMap.find(test_id2); + CPPUNIT_ASSERT(iter_idset == _mainbuffer._callIDMap.end()); + + ringbuffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 1); + iter_readpointer = ringbuffer->_readpointer.find(test_id1); + CPPUNIT_ASSERT(iter_readpointer->first == test_id1); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = ringbuffer->_readpointer.find(test_id2); + CPPUNIT_ASSERT(iter_readpointer == ringbuffer->_readpointer.end()); + + ringbuffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 1); + iter_readpointer = ringbuffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = ringbuffer->_readpointer.find(test_id2); + CPPUNIT_ASSERT(iter_readpointer == ringbuffer->_readpointer.end()); + + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(test_id2) == NULL); + + + _mainbuffer.unBindCallID(default_id, test_id1); + + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 0); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 0); + + // test unbind all function + _mainbuffer.bindCallID(default_id, test_id1); + _mainbuffer.bindCallID(default_id, test_id2); + _mainbuffer.bindCallID(test_id1, test_id2); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 3); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 3); + + _mainbuffer.unBindAll(test_id2); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 2); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 2); + + iter_buffer = _mainbuffer._ringBufferMap.find(default_id); + CPPUNIT_ASSERT(iter_buffer->first == default_id); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(default_id)); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id1); + CPPUNIT_ASSERT(iter_buffer->first == test_id1); + CPPUNIT_ASSERT(iter_buffer->second == _mainbuffer.getRingBuffer(test_id1)); + + iter_buffer = _mainbuffer._ringBufferMap.find(test_id2); + CPPUNIT_ASSERT(iter_buffer == _mainbuffer._ringBufferMap.end()); + + iter_idset = _mainbuffer._callIDMap.find(default_id); + CPPUNIT_ASSERT(iter_idset->second->size() == 1); + iter_id = iter_idset->second->find(test_id1); + CPPUNIT_ASSERT(*iter_id == test_id1); + iter_id = iter_idset->second->find(test_id2); + CPPUNIT_ASSERT(iter_id == iter_idset->second->end()); + + iter_idset = _mainbuffer._callIDMap.find(test_id1); + CPPUNIT_ASSERT(iter_idset->second->size() == 1); + iter_id = iter_idset->second->find(default_id); + CPPUNIT_ASSERT(*iter_id == default_id); + + iter_idset = _mainbuffer._callIDMap.find(test_id2); + CPPUNIT_ASSERT(iter_idset == _mainbuffer._callIDMap.end()); + + ringbuffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 1); + iter_readpointer = ringbuffer->_readpointer.find(test_id1); + CPPUNIT_ASSERT(iter_readpointer->first == test_id1); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = ringbuffer->_readpointer.find(test_id2); + CPPUNIT_ASSERT(iter_readpointer == ringbuffer->_readpointer.end()); + + ringbuffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(ringbuffer != NULL); + CPPUNIT_ASSERT(ringbuffer->getNbReadPointer() == 1); + iter_readpointer = ringbuffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = ringbuffer->_readpointer.find(test_id2); + CPPUNIT_ASSERT(iter_readpointer == ringbuffer->_readpointer.end()); + + +} + +void MainBufferTest::testGetPutDataByID() +{ + + _debug("MainBufferTest::testGetPutData()\n"); + + CallID test_id = "getData putData"; + CallID false_id = "false id"; + + _mainbuffer.bindCallID(test_id); + + int test_input1 = 12; + int test_input2 = 13; + int test_output; + + int avail_for_put_testid; + int avail_for_put_defaultid; + + // put by default_id get by test_id without preleminary put + avail_for_put_defaultid = _mainbuffer.availForPut(); + CPPUNIT_ASSERT(_mainbuffer.availForGetByID(default_id, test_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.getDataByID(&test_output, sizeof(int), 100, default_id, test_id) == 0); + + // put by default_id, get by test_id + CPPUNIT_ASSERT(_mainbuffer.availForPut() == avail_for_put_defaultid); + CPPUNIT_ASSERT(_mainbuffer.putData(&test_input1, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForPut() == (avail_for_put_defaultid - (int)sizeof(int))); + CPPUNIT_ASSERT(_mainbuffer.availForGetByID(default_id, test_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.getDataByID(&test_output, sizeof(int), 100, default_id, test_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGetByID(default_id, test_id) == 0); + CPPUNIT_ASSERT(test_input1 == test_output); + + // get by default_id without preliminary input + avail_for_put_testid = _mainbuffer.availForPut(test_id); + CPPUNIT_ASSERT(_mainbuffer.availForGetByID(test_id, default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.getDataByID(&test_output, sizeof(int), 100, test_id, default_id) == 0); + + // pu by test_id get by test_id + CPPUNIT_ASSERT(_mainbuffer.availForPut(test_id) == avail_for_put_defaultid); + CPPUNIT_ASSERT(_mainbuffer.putData(&test_input2, sizeof(int), 100, test_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGetByID(test_id, default_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.getDataByID(&test_output, sizeof(int), 100, test_id, default_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGetByID(test_id, default_id) == 0); + CPPUNIT_ASSERT(test_input2 == test_output); + + // put/get by false id + CPPUNIT_ASSERT(_mainbuffer.putData(&test_input2, sizeof(int), 100, false_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.getDataByID(&test_input2, sizeof(int), 100, false_id, false_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.getDataByID(&test_input2, sizeof(int), 100, default_id, false_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.getDataByID(&test_input2, sizeof(int), 100, false_id, default_id) == 0); + + _mainbuffer.unBindCallID(test_id); + +} + + + +void MainBufferTest::testGetPutData() +{ + + _debug("MainBufferTest::testGetDataAndCallID()\n"); + + CallID test_id = "incoming rtp session"; + + _mainbuffer.bindCallID(test_id); + + int test_input1 = 12; + int test_input2 = 13; + int test_output; + + int avail_for_put_testid; + int avail_for_put_defaultid; + + // get by test_id without preleminary put + avail_for_put_defaultid = _mainbuffer.availForPut(); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.getData(&test_output, sizeof(int), 100, test_id) == 0); + + // put by default_id, get by test_id + CPPUNIT_ASSERT(_mainbuffer.availForPut() == avail_for_put_defaultid); + CPPUNIT_ASSERT(_mainbuffer.putData(&test_input1, sizeof(int), 100) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForPut() == (avail_for_put_defaultid - (int)sizeof(int))); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.getData(&test_output, sizeof(int), 100, test_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id) == 0); + CPPUNIT_ASSERT(test_input1 == test_output); + + // get by default_id without preleminary put + avail_for_put_testid = _mainbuffer.availForPut(test_id); + CPPUNIT_ASSERT(_mainbuffer.availForGet() == 0); + CPPUNIT_ASSERT(_mainbuffer.getData(&test_output, sizeof(int)) == 0); + + // put by test_id, get by default_id + CPPUNIT_ASSERT(_mainbuffer.availForPut(test_id) == avail_for_put_testid); + CPPUNIT_ASSERT(_mainbuffer.putData(&test_input2, sizeof(int), 100, test_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForPut(test_id) == (avail_for_put_testid - (int)sizeof(int))); + CPPUNIT_ASSERT(_mainbuffer.availForGet() == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.getData(&test_output, sizeof(int), 100) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet() == 0); + CPPUNIT_ASSERT(test_input2 == test_output); + + _mainbuffer.unBindCallID(test_id); + +} + + +void MainBufferTest::testDiscardFlush() +{ + + _debug("MainBufferTest::testDiscardFlush()\n"); + + CallID test_id = "flush discard"; + // _mainbuffer.createRingBuffer(test_id); + _mainbuffer.bindCallID(test_id); + + int test_input1 = 12; + // int test_output_size; + // int init_size; + + CPPUNIT_ASSERT(_mainbuffer.putData(&test_input1, sizeof(int), 100, test_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet() == sizeof(int)); + _mainbuffer.discard(sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet() == 0); + + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id) == 0); + _mainbuffer.discard(sizeof(int), test_id); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id) == 0); + + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(test_id)->getReadPointer(default_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(test_id)->getReadPointer(test_id) == 0); + + + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(default_id)->getReadPointer(test_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.putData(&test_input1, sizeof(int), 100) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(default_id)->getReadPointer(test_id) == 0); + + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id) == sizeof(int)); + + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(default_id)->getReadPointer(test_id) == 0); + _mainbuffer.discard(sizeof(int), test_id); + CPPUNIT_ASSERT(_mainbuffer.getRingBuffer(default_id)->getReadPointer(test_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id) == 0); + + // _mainbuffer.removeRingBuffer(test_id); + _mainbuffer.unBindCallID(test_id); + +} + + +void MainBufferTest::testReadPointerInit() +{ + + _debug("MainBufferTest::testReadPointerInit()\n"); + + CallID test_id = "test read pointer init"; + // RingBuffer* test_ring_buffer = _mainbuffer.createRingBuffer(test_id); + + _mainbuffer.bindCallID(test_id); + + RingBuffer* test_ring_buffer = _mainbuffer.getRingBuffer(test_id); + + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 0); + test_ring_buffer->storeReadPointer(30); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer() == 30); + + test_ring_buffer->createReadPointer(test_id); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 0); + test_ring_buffer->storeReadPointer(10, test_id); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 10); + test_ring_buffer->removeReadPointer(test_id); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == (int)NULL); + test_ring_buffer->removeReadPointer("false id"); + + // _mainbuffer.removeRingBuffer(test_id); + _mainbuffer.unBindCallID(test_id); +} + + +void MainBufferTest::testRingBufferSeveralPointers() +{ + + _debug("MainBufferTest::testRingBufferSeveralPointers\n"); + + CallID test_id = "test multiple read pointer"; + RingBuffer* test_ring_buffer = _mainbuffer.createRingBuffer(test_id); + + CallID test_pointer1 = "test pointer 1"; + CallID test_pointer2 = "test pointer 2"; + + test_ring_buffer->createReadPointer(test_pointer1); + test_ring_buffer->createReadPointer(test_pointer2); + + int testint1 = 12; + int testint2 = 13; + int testint3 = 14; + int testint4 = 15; + + int testoutput; + + int initPutLen = test_ring_buffer->AvailForPut(); + + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint1, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == initPutLen - (int)sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_pointer1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_pointer2) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer2) == sizeof(int)); + + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint2, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == initPutLen - 2*(int)sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_pointer1) == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_pointer2) == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer1) == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer2) == 2*sizeof(int)); + + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint3, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 3*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == initPutLen - 3*(int)sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_pointer1) == 3*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_pointer2) == 3*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer1) == 3*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer2) == 3*sizeof(int)); + + CPPUNIT_ASSERT(test_ring_buffer->Put(&testint4, sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 4*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == initPutLen - 4*(int)sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_pointer1) == 4*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getLen(test_pointer2) == 4*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer1) == 4*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer2) == 4*sizeof(int)); + + + CPPUNIT_ASSERT(test_ring_buffer->Get(&testoutput, sizeof(int), 100, test_pointer1) == sizeof(int)); + CPPUNIT_ASSERT(testoutput == testint1); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == initPutLen - 4*(int)sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer1) == 3*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer2) == 4*sizeof(int)); + + CPPUNIT_ASSERT(test_ring_buffer->Get(&testoutput, sizeof(int), 100, test_pointer2) == sizeof(int)); + CPPUNIT_ASSERT(testoutput == testint1); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == initPutLen - 3*(int)sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer1) == 3*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer2) == 3*sizeof(int)); + + // AvailForPut() is ok but AvailForGet(default_id) is not ok + // However, we should no be alowed to read in our own ring buffer + // if we are either an AudioLayer or and RTP session + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == 4*sizeof(int)); + + CPPUNIT_ASSERT(test_ring_buffer->Get(&testoutput, sizeof(int), 100, test_pointer1) == sizeof(int)); + CPPUNIT_ASSERT(testoutput == testint2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == initPutLen - 3*(int)sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer1) == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer2) == 3*sizeof(int)); + + // AvailForPut() is ok but AvailForGet(default_id) is not ok + // However, we should no be alowed to read in our own ring buffer + // if we are either an AudioLayer or and RTP session + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == 4*sizeof(int)); + + CPPUNIT_ASSERT(test_ring_buffer->Get(&testoutput, sizeof(int), 100, test_pointer2) == sizeof(int)); + CPPUNIT_ASSERT(testoutput == testint2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == initPutLen - 2*(int)sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer1) == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer2) == 2*sizeof(int)); + + // AvailForPut() is ok but AvailForGet(default_id) is not ok + // However, we should no be alowed to read in our own ring buffer + // if we are either an AudioLayer or and RTP session + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet() == 4*sizeof(int)); + + CPPUNIT_ASSERT(test_ring_buffer->Discard(sizeof(int), test_pointer1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == initPutLen - 2*(int)sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer2) == 2*sizeof(int)); + + CPPUNIT_ASSERT(test_ring_buffer->Discard(sizeof(int), test_pointer2) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == initPutLen - (int)sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_pointer2) == sizeof(int)); + + + test_ring_buffer->removeReadPointer(test_pointer1); + test_ring_buffer->removeReadPointer(test_pointer2); + + _mainbuffer.removeRingBuffer(test_id); +} + + + +void MainBufferTest::testConference() +{ + + _debug("MainBufferTest::testConference()\n"); + + CallID test_id1 = "participant A"; + CallID test_id2 = "participant B"; + RingBuffer* test_ring_buffer; + + RingBufferMap::iterator iter_ringbuffermap; + ReadPointer::iterator iter_readpointer; + CallIDMap::iterator iter_callidmap; + CallIDSet::iterator iter_callidset; + + + + // test initial setup + // ringbuffers + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer == NULL); + + // callidmap + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 0); + iter_callidmap = _mainbuffer._callIDMap.find(default_id); + CPPUNIT_ASSERT(iter_callidmap == _mainbuffer._callIDMap.end()); + + + // test bind Participant A with default + _mainbuffer.bindCallID(test_id1); + // ringbuffers + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 2); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 1); + iter_readpointer = test_ring_buffer->_readpointer.find(test_id1); + CPPUNIT_ASSERT(iter_readpointer->first == test_id1); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 1); + iter_readpointer = test_ring_buffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + // callidmap + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 2); + iter_callidmap = _mainbuffer._callIDMap.find(default_id); + CPPUNIT_ASSERT(iter_callidmap->first == default_id); + CPPUNIT_ASSERT(iter_callidmap->second->size() == 1); + iter_callidset = iter_callidmap->second->find(test_id1); + CPPUNIT_ASSERT(*iter_callidset == test_id1); + iter_callidmap = _mainbuffer._callIDMap.find(test_id1); + CPPUNIT_ASSERT(iter_callidmap->first == test_id1); + CPPUNIT_ASSERT(iter_callidmap->second->size() == 1); + iter_callidset = iter_callidmap->second->find(default_id); + CPPUNIT_ASSERT(*iter_callidset == default_id); + + // test bind Participant B with default + _mainbuffer.bindCallID(test_id2); + // ringbuffers + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 3); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 2); + iter_readpointer = test_ring_buffer->_readpointer.find(test_id1); + CPPUNIT_ASSERT(iter_readpointer->first == test_id1); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = test_ring_buffer->_readpointer.find(test_id2); + CPPUNIT_ASSERT(iter_readpointer->first == test_id2); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 1); + iter_readpointer = test_ring_buffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 1); + iter_readpointer = test_ring_buffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + // callidmap + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 3); + iter_callidmap = _mainbuffer._callIDMap.find(default_id); + CPPUNIT_ASSERT(iter_callidmap->first == default_id); + CPPUNIT_ASSERT(iter_callidmap->second->size() == 2); + iter_callidset = iter_callidmap->second->find(test_id1); + CPPUNIT_ASSERT(*iter_callidset == test_id1); + iter_callidset = iter_callidmap->second->find(test_id2); + CPPUNIT_ASSERT(*iter_callidset == test_id2); + iter_callidmap = _mainbuffer._callIDMap.find(test_id1); + CPPUNIT_ASSERT(iter_callidmap->first == test_id1); + CPPUNIT_ASSERT(iter_callidmap->second->size() == 1); + iter_callidset = iter_callidmap->second->find(default_id); + CPPUNIT_ASSERT(*iter_callidset == default_id); + iter_callidmap = _mainbuffer._callIDMap.find(test_id2); + CPPUNIT_ASSERT(iter_callidmap->first == test_id2); + CPPUNIT_ASSERT(iter_callidmap->second->size() == 1); + iter_callidset = iter_callidmap->second->find(default_id); + CPPUNIT_ASSERT(*iter_callidset == default_id); + + + // test bind Participant A with Participant B + _mainbuffer.bindCallID(test_id1, test_id2); + // ringbuffers + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 3); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 2); + iter_readpointer = test_ring_buffer->_readpointer.find(test_id1); + CPPUNIT_ASSERT(iter_readpointer->first == test_id1); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = test_ring_buffer->_readpointer.find(test_id2); + CPPUNIT_ASSERT(iter_readpointer->first == test_id2); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 2); + iter_readpointer = test_ring_buffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = test_ring_buffer->_readpointer.find(test_id2); + CPPUNIT_ASSERT(iter_readpointer->first == test_id2); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->getNbReadPointer() == 2); + iter_readpointer = test_ring_buffer->_readpointer.find(default_id); + CPPUNIT_ASSERT(iter_readpointer->first == default_id); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + iter_readpointer = test_ring_buffer->_readpointer.find(test_id1); + CPPUNIT_ASSERT(iter_readpointer->first == test_id1); + CPPUNIT_ASSERT(iter_readpointer->second == 0); + // callidmap + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 3); + iter_callidmap = _mainbuffer._callIDMap.find(default_id); + CPPUNIT_ASSERT(iter_callidmap->first == default_id); + CPPUNIT_ASSERT(iter_callidmap->second->size() == 2); + iter_callidset = iter_callidmap->second->find(test_id1); + CPPUNIT_ASSERT(*iter_callidset == test_id1); + iter_callidset = iter_callidmap->second->find(test_id2); + CPPUNIT_ASSERT(*iter_callidset == test_id2); + iter_callidmap = _mainbuffer._callIDMap.find(test_id1); + CPPUNIT_ASSERT(iter_callidmap->first == test_id1); + CPPUNIT_ASSERT(iter_callidmap->second->size() == 2); + iter_callidset = iter_callidmap->second->find(default_id); + CPPUNIT_ASSERT(*iter_callidset == default_id); + iter_callidset = iter_callidmap->second->find(test_id2); + CPPUNIT_ASSERT(*iter_callidset == test_id2); + iter_callidmap = _mainbuffer._callIDMap.find(test_id2); + CPPUNIT_ASSERT(iter_callidmap->first == test_id2); + CPPUNIT_ASSERT(iter_callidmap->second->size() == 2); + iter_callidset = iter_callidmap->second->find(default_id); + CPPUNIT_ASSERT(*iter_callidset == default_id); + iter_callidset = iter_callidmap->second->find(test_id1); + CPPUNIT_ASSERT(*iter_callidset == test_id1); + + + // test putData default + int testint = 12; + int init_put_defaultid; + int init_put_id1; + int init_put_id2; + + init_put_defaultid = _mainbuffer.getRingBuffer(default_id)->AvailForPut(); + init_put_id1 = _mainbuffer.getRingBuffer(test_id1)->AvailForPut(); + init_put_id2 = _mainbuffer.getRingBuffer(test_id2)->AvailForPut(); + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == 0); + // put data test ring buffers + CPPUNIT_ASSERT(_mainbuffer.putData(&testint, sizeof(int), 100) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id1); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == 0); + //putdata test ring buffers + CPPUNIT_ASSERT(_mainbuffer.putData(&testint, sizeof(int), 100, test_id1) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + //putdata test ring buffers + CPPUNIT_ASSERT(_mainbuffer.putData(&testint, sizeof(int), 100, test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id2 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + + + int test_output; + + // test getData default id (audio layer) + CPPUNIT_ASSERT(_mainbuffer.getData(&test_output, sizeof(int), 100) == sizeof(int)); + CPPUNIT_ASSERT(test_output == (testint + testint)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id2 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + // test getData test_id1 (audio layer) + CPPUNIT_ASSERT(_mainbuffer.getData(&test_output, sizeof(int), 100, test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_output == (testint + testint)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + // test getData test_id2 (audio layer) + CPPUNIT_ASSERT(_mainbuffer.getData(&test_output, sizeof(int), 100, test_id2) == sizeof(int)); + CPPUNIT_ASSERT(test_output == (testint + testint)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_defaultid); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id1); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == 0); + + + // test putData default (for discarting) + init_put_defaultid = _mainbuffer.getRingBuffer(default_id)->AvailForPut(); + init_put_id1 = _mainbuffer.getRingBuffer(test_id1)->AvailForPut(); + init_put_id2 = _mainbuffer.getRingBuffer(test_id2)->AvailForPut(); + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == 0); + // put data test ring buffers + CPPUNIT_ASSERT(_mainbuffer.putData(&testint, sizeof(int), 100) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id1); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == 0); + //putdata test ring buffers + CPPUNIT_ASSERT(_mainbuffer.putData(&testint, sizeof(int), 100, test_id1) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + //putdata test ring buffers + CPPUNIT_ASSERT(_mainbuffer.putData(&testint, sizeof(int), 100, test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id2 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + + // test discardData default id (audio layer) + CPPUNIT_ASSERT(_mainbuffer.discard(sizeof(int)) == sizeof(int)); + CPPUNIT_ASSERT(test_output == (testint + testint)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id2 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + // test discardData test_id1 (audio layer) + CPPUNIT_ASSERT(_mainbuffer.discard(sizeof(int), test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_output == (testint + testint)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + // test discardData test_id2 (audio layer) + CPPUNIT_ASSERT(_mainbuffer.discard(sizeof(int), test_id2) == sizeof(int)); + CPPUNIT_ASSERT(test_output == (testint + testint)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_defaultid); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id1); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == 0); + + + // test putData default (for flushing) + init_put_defaultid = _mainbuffer.getRingBuffer(default_id)->AvailForPut(); + init_put_id1 = _mainbuffer.getRingBuffer(test_id1)->AvailForPut(); + init_put_id2 = _mainbuffer.getRingBuffer(test_id2)->AvailForPut(); + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == 0); + // put data test ring buffers + CPPUNIT_ASSERT(_mainbuffer.putData(&testint, sizeof(int), 100) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id1); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == 0); + //putdata test ring buffers + CPPUNIT_ASSERT(_mainbuffer.putData(&testint, sizeof(int), 100, test_id1) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + //putdata test ring buffers + CPPUNIT_ASSERT(_mainbuffer.putData(&testint, sizeof(int), 100, test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id2 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + + // test flush default id (audio layer) + _mainbuffer.flush(); + CPPUNIT_ASSERT(test_output == (testint + testint)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + _debug("%i\n", test_ring_buffer->putLen()); + test_ring_buffer->debug(); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id2 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == sizeof(int)); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == sizeof(int)); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + // test flush test_id1 (audio layer) + _mainbuffer.flush(test_id1); + CPPUNIT_ASSERT(test_output == (testint + testint)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_defaultid - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == (int)(init_put_id1 - sizeof(int))); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == sizeof(int)); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == sizeof(int)); + // test flush test_id2 (audio layer) + _mainbuffer.flush(test_id2); + CPPUNIT_ASSERT(test_output == (testint + testint)); + test_ring_buffer = _mainbuffer.getRingBuffer(default_id); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_defaultid); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id1); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id1); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id2) == 0); + test_ring_buffer = _mainbuffer.getRingBuffer(test_id2); + CPPUNIT_ASSERT(test_ring_buffer->putLen() == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForPut() == init_put_id2); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(default_id) == 0); + CPPUNIT_ASSERT(test_ring_buffer->AvailForGet(test_id1) == 0); + // test mainbuffer availforget + CPPUNIT_ASSERT(_mainbuffer.availForGet(default_id) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id1) == 0); + CPPUNIT_ASSERT(_mainbuffer.availForGet(test_id2) == 0); + + + _mainbuffer.unBindCallID(test_id1, test_id2); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 3); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 3); + + _mainbuffer.unBindCallID(test_id1); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 2); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 2); + + _mainbuffer.unBindCallID(test_id2); + CPPUNIT_ASSERT(_mainbuffer._ringBufferMap.size() == 0); + CPPUNIT_ASSERT(_mainbuffer._callIDMap.size() == 0); + + +} diff --git a/sflphone-common/test/mainbufferTest.h b/sflphone-common/test/mainbufferTest.h new file mode 100644 index 0000000000000000000000000000000000000000..330228f9a92d011d4540f74a4cb902c1ff525c20 --- /dev/null +++ b/sflphone-common/test/mainbufferTest.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +// Cppunit import +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCaller.h> +#include <cppunit/TestCase.h> +#include <cppunit/TestSuite.h> + +#include <assert.h> + +#include <stdio.h> +#include <sstream> +#include <ccrtp/rtp.h> + + +// pjsip import +#include <pjsip.h> +#include <pjlib.h> +#include <pjsip_ua.h> +#include <pjlib-util.h> +#include <pjnath/stun_config.h> + +// Application import +#include "manager.h" +#include "audio/mainbuffer.h" +#include "audio/ringbuffer.h" +#include "call.h" +// #include "config/config.h" +// #include "user_cfg.h" + + + +/* + * @file audiorecorderTest.cpp + * @brief Regroups unitary tests related to the plugin manager. + */ + +#ifndef _MAINBUFFER_TEST_ +#define _MAINBUFFER_TEST_ + + + +class MainBufferTest : public CppUnit::TestCase { + + /* + * Use cppunit library macros to add unit test the factory + */ + CPPUNIT_TEST_SUITE( MainBufferTest ); + CPPUNIT_TEST( testRingBufferCreation ); + CPPUNIT_TEST( testRingBufferReadPointer ); + CPPUNIT_TEST( testCallIDSet ); + CPPUNIT_TEST( testRingBufferInt ); + CPPUNIT_TEST( testRingBufferNonDefaultID ); + CPPUNIT_TEST( testRingBufferFloat ); + CPPUNIT_TEST( testTwoPointer ); + CPPUNIT_TEST( testBindUnbindBuffer ); + CPPUNIT_TEST( testGetPutDataByID ); + CPPUNIT_TEST( testGetPutData ); + CPPUNIT_TEST( testDiscardFlush ); + CPPUNIT_TEST( testReadPointerInit ); + CPPUNIT_TEST( testRingBufferSeveralPointers ); + CPPUNIT_TEST( testConference ); + CPPUNIT_TEST_SUITE_END(); + + public: + + MainBufferTest() : CppUnit::TestCase("Audio Layer Tests") {} + + /* + * Code factoring - Common resources can be initialized here. + * This method is called by unitcpp before each test + */ + void setUp(); + + /* + * Code factoring - Common resources can be released here. + * This method is called by unitcpp after each test + */ + inline void tearDown(); + + void testRingBufferCreation(); + + void testRingBufferReadPointer(); + + void testCallIDSet(); + + void testRingBufferInt(); + + void testRingBufferNonDefaultID(); + + void testRingBufferFloat(); + + void testTwoPointer(); + + void testBindUnbindBuffer(); + + void testGetPutDataByID(); + + void testGetPutData(); + + void testAvailForGetPut(); + + void testDiscardFlush(); + + void testReadPointerInit(); + + void testRingBufferSeveralPointers(); + + void testConference(); + + private: + + MainBuffer _mainbuffer; +}; + +/* Register our test module */ +CPPUNIT_TEST_SUITE_REGISTRATION( MainBufferTest ); + +#endif diff --git a/sflphone-common/test/numbercleanerTest.h b/sflphone-common/test/numbercleanerTest.h index 3152892a0053bcbb43b4e347933bc1bb576b2bca..3af6ab8c92a59e3125dd1d7d2aa2d9d648e32b2f 100644 --- a/sflphone-common/test/numbercleanerTest.h +++ b/sflphone-common/test/numbercleanerTest.h @@ -27,7 +27,7 @@ // Application import #include "numbercleaner.h" - +// #include "../src/conference.h" /* * @file numbercleanerTest.cpp * @brief Regroups unitary tests related to the phone number cleanup function. diff --git a/sflphone-common/test/rtpTest.cpp b/sflphone-common/test/rtpTest.cpp index fba3f8aeb3adb7706dc05e415226983654a856cf..4a4d313314d20bdb6642bc7383deae0fd0f267a1 100644 --- a/sflphone-common/test/rtpTest.cpp +++ b/sflphone-common/test/rtpTest.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Savoir-Faire Linux inc. - * Author: Alexandre Savarda <emmanuel.milou@savoirfairelinux.com> + * Author: Alexandre Savarda <alexandre.savard@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by