diff --git a/apps/webconference/RoomInfo.cpp b/apps/webconference/RoomInfo.cpp index dc08d492..80ced1e6 100644 --- a/apps/webconference/RoomInfo.cpp +++ b/apps/webconference/RoomInfo.cpp @@ -29,6 +29,7 @@ AmArg ConferenceRoomParticipant::asArgArray() { res.push(AmArg((int)status)); res.push(AmArg(last_reason.c_str())); res.push(AmArg((int)muted)); + res.push(AmArg(participant_id)); return res; } @@ -45,7 +46,9 @@ void ConferenceRoomParticipant::updateStatus(ConferenceRoomParticipant::Particip updateAccess(now); } -ConferenceRoom::ConferenceRoom() { +ConferenceRoom::ConferenceRoom() + : expiry_time(0) +{ gettimeofday(&last_access_time, NULL); } @@ -91,12 +94,14 @@ vector ConferenceRoom::participantLtags() { } void ConferenceRoom::newParticipant(const string& localtag, - const string& number) { + const string& number, + const string& participant_id) { gettimeofday(&last_access_time, NULL); participants.push_back(ConferenceRoomParticipant()); participants.back().localtag = localtag; participants.back().number = number; + participants.back().participant_id = participant_id; } bool ConferenceRoom::hasParticipant(const string& localtag) { diff --git a/apps/webconference/RoomInfo.h b/apps/webconference/RoomInfo.h index 4e3b33d4..6be0aabb 100644 --- a/apps/webconference/RoomInfo.h +++ b/apps/webconference/RoomInfo.h @@ -31,6 +31,7 @@ struct ConferenceRoomParticipant { string number; ParticipantStatus status; string last_reason; + string participant_id; int muted; @@ -70,7 +71,8 @@ struct ConferenceRoom { vector participantLtags(); - void newParticipant(const string& localtag, const string& number); + void newParticipant(const string& localtag, const string& number, + const string& participant_id); bool updateStatus(const string& part_tag, ConferenceRoomParticipant::ParticipantStatus newstatus, diff --git a/apps/webconference/WebConference.cpp b/apps/webconference/WebConference.cpp index ac205b99..ba6ccd9a 100644 --- a/apps/webconference/WebConference.cpp +++ b/apps/webconference/WebConference.cpp @@ -72,6 +72,9 @@ bool WebConferenceFactory::ignore_pin = false; bool WebConferenceFactory::PrivateRoomsMode = false; +string WebConferenceFactory::participant_id_paramname; // default: param not used +string WebConferenceFactory::participant_id_hdr = "X-ParticipantID"; // default header + int WebConferenceFactory::onLoad() { return getInstance()->load(); @@ -90,6 +93,11 @@ int WebConferenceFactory::load() // get application specific global parameters configureModule(cfg); + + participant_id_paramname = cfg.getParameter("participant_id_param"); + if (cfg.hasParameter("participant_id_header")) + participant_id_hdr = cfg.getParameter("participant_id_header"); + // get prompts AM_PROMPT_START; AM_PROMPT_ADD(FIRST_PARTICIPANT, WEBCONF_ANNOUNCE_PATH "first_paricipant.wav"); @@ -243,14 +251,15 @@ bool WebConferenceFactory::isValidConference(const string& conf_id) { bool WebConferenceFactory::newParticipant(const string& conf_id, const string& localtag, - const string& number) { + const string& number, + const string& participant_id) { rooms_mut.lock(); if (PrivateRoomsMode && rooms.find(conf_id) == rooms.end()) { rooms_mut.unlock(); return false; } - rooms[conf_id].newParticipant(localtag, number); + rooms[conf_id].newParticipant(localtag, number, participant_id); rooms_mut.unlock(); return true; } @@ -471,6 +480,10 @@ void WebConferenceFactory::invoke(const string& method, args.assertArrayFmt("s"); listRooms(args, ret); ret.push(getServerInfoString().c_str()); + } else if(method == "findParticipant"){ + args.assertArrayFmt("s"); + findParticipant(args, ret); + ret.push(getServerInfoString().c_str()); } else if(method == "_list"){ ret.push("roomCreate"); ret.push("roomDelete"); @@ -486,6 +499,7 @@ void WebConferenceFactory::invoke(const string& method, ret.push("vqRoomFeedback"); ret.push("getRoomPassword"); ret.push("listRooms"); + ret.push("findParticipant"); } else throw AmDynInvoke::NotImplemented(method); } @@ -653,6 +667,7 @@ void WebConferenceFactory::dialout(const AmArg& args, AmArg& ret) { string auth_pwd = args.get(6).asCStr(); string callee_domain = domain; string headers; + string participant_id; if (args.size()>7) { try { @@ -679,6 +694,16 @@ void WebConferenceFactory::dialout(const AmArg& args, AmArg& ret) { callee_domain = domain; } } + + if (args.size()>9) { + try { + assertArgCStr(args.get(9)); + participant_id = args.get(9).asCStr(); + } + catch (AmArg::TypeMismatchException &e) { + participant_id = ""; + } + } } string from = "sip:" + from_user + "@" + domain; @@ -694,10 +719,10 @@ void WebConferenceFactory::dialout(const AmArg& args, AmArg& ret) { rooms_mut.unlock(); if (!is_valid_room) { - ret.push(1); - ret.push("wrong adminpin or inexisting room"); - ret.push(""); - return; + ret.push(1); + ret.push("wrong adminpin or inexisting room"); + ret.push(""); + return; } DBG("dialout webconference room '%s', from '%s', to '%s'", @@ -716,7 +741,7 @@ void WebConferenceFactory::dialout(const AmArg& args, AmArg& ret) { ret.push(0); ret.push("OK"); ret.push(localtag.c_str()); - newParticipant(room, localtag, to); + newParticipant(room, localtag, to, participant_id); updateStatus(room, localtag, ConferenceRoomParticipant::Connecting, "INVITE"); @@ -869,6 +894,25 @@ void WebConferenceFactory::listRooms(const AmArg& args, AmArg& ret) { ret.push(room_list); } +void WebConferenceFactory::findParticipant(const AmArg& args, AmArg& ret) { + string participant_id = args.get(0).asCStr(); + AmArg r_ret; + r_ret.assertArray(); + rooms_mut.lock(); + for (map::iterator it = + rooms.begin(); it != rooms.end(); it++) { + for (list::iterator p_it= + it->second.participants.begin(); p_it != it->second.participants.end(); p_it++) { + if (p_it->participant_id == participant_id) { + r_ret.push(it->first); + break; + } + } + } + rooms_mut.unlock(); + ret.push(r_ret); +} + void WebConferenceFactory::vqRoomFeedback(const AmArg& args, AmArg& ret) { string room = args.get(0).asCStr(); string adminpin = args.get(1).asCStr(); diff --git a/apps/webconference/WebConference.h b/apps/webconference/WebConference.h index 2d251931..1c5a5a68 100644 --- a/apps/webconference/WebConference.h +++ b/apps/webconference/WebConference.h @@ -137,6 +137,13 @@ public: static bool PrivateRoomsMode; + // P-App-Param parameter to get participant ID from + static string participant_id_paramname; + // if participant_id_paramname not configured: + // header to get participant ID from + static string participant_id_hdr; + + WebConferenceFactory(const string& _app_name); AmSession* onInvite(const AmSipRequest&); AmSession* onInvite(const AmSipRequest& req, @@ -146,7 +153,8 @@ public: bool isValidConference(const string& conf_id); bool newParticipant(const string& conf_id, const string& localtag, - const string& number); + const string& number, + const string& participant_id); void updateStatus(const string& conf_id, const string& localtag, ConferenceRoomParticipant::ParticipantStatus status, @@ -186,6 +194,8 @@ public: void getRoomPassword(const AmArg& args, AmArg& ret); void listRooms(const AmArg& args, AmArg& ret); + void findParticipant(const AmArg& args, AmArg& ret); + }; diff --git a/apps/webconference/WebConferenceDialog.cpp b/apps/webconference/WebConferenceDialog.cpp index 9431d890..7622cc3f 100644 --- a/apps/webconference/WebConferenceDialog.cpp +++ b/apps/webconference/WebConferenceDialog.cpp @@ -112,6 +112,22 @@ void WebConferenceDialog::connectConference(const string& room) { void WebConferenceDialog::onSessionStart(const AmSipRequest& req) { time(&connect_ts); + if (WebConferenceFactory::participant_id_paramname.length()) { + string appparams = getHeader(req.hdrs, PARAM_HDR); + if (appparams.length()) { + participant_id = get_header_param(appparams, + WebConferenceFactory::participant_id_paramname); + } + } else if (WebConferenceFactory::participant_id_hdr.length()) { + participant_id = getHeader(req.hdrs, WebConferenceFactory::participant_id_hdr); + } + + if (participant_id.empty()) { + DBG("no Participant ID set\n"); + } else { + DBG("Participant ID set to '%s'\n", participant_id.c_str()); + } + // direct room access? if (conf_id.empty()) { state = EnteringPin; @@ -122,7 +138,8 @@ void WebConferenceDialog::onSessionStart(const AmSipRequest& req) { DBG("########## direct connect conference #########\n"); if (!factory->newParticipant(conf_id, getLocalTag(), - dlg.remote_party)) { + dlg.remote_party, + participant_id)) { DBG("inexisting conference room\n"); state = PlayErrorFinish; setInOut(&play_list,&play_list); @@ -276,7 +293,8 @@ void WebConferenceDialog::process(AmEvent* ev) if (!factory->newParticipant(pin_str, getLocalTag(), - dlg.remote_party)) { + dlg.remote_party, + participant_id)) { DBG("inexisting conference room\n"); state = PlayErrorFinish; setInOut(&play_list,&play_list); diff --git a/apps/webconference/WebConferenceDialog.h b/apps/webconference/WebConferenceDialog.h index 23cb4796..4923792b 100644 --- a/apps/webconference/WebConferenceDialog.h +++ b/apps/webconference/WebConferenceDialog.h @@ -83,6 +83,9 @@ private: time_t connect_ts; time_t disconnect_ts; + // ID from X-ParticipantID header + string participant_id; + public: WebConferenceDialog(AmPromptCollection& prompts, WebConferenceFactory* my_f, diff --git a/apps/webconference/etc/webconference.conf b/apps/webconference/etc/webconference.conf index 5b53d1f7..cc0ec9a8 100644 --- a/apps/webconference/etc/webconference.conf +++ b/apps/webconference/etc/webconference.conf @@ -131,6 +131,16 @@ stats_dir=/var/log/sems-webconference/ # # predefined_rooms=discussion:some_pwd;support:other_pwd; + +# Participant ID (default: X-ParticipantID header) +# +# get participant ID from P-App-Param: +#participant_id_param=participantid +# +# or, get participant ID from header: +#participant_id_header=x-participantid + + ############################################################### # RFC4028 Session Timer # diff --git a/doc/Readme.webconference.txt b/doc/Readme.webconference.txt index 78512f53..5d085d22 100644 --- a/doc/Readme.webconference.txt +++ b/doc/Readme.webconference.txt @@ -57,6 +57,19 @@ If a room exists and the adminpin is not set (for example if the room is created by dial-in), the first call to roomInfo/dialout/kick/... with room/adminpin will set the adminpin. +Participant ID +-------------- + +In some service environments, it may be necessary to determine in which conference +rooms a certain user is at the moment. For example, if the active conferences of a +user should be displayed on a web page, the conference bridge may be queried for the +room a user is in. + +The findParticipant(string participant_id) function returns a list of rooms where the +participant with a given ID is in. This participant ID can be given with + - a parameter to the dialout() function + - a header or P-App-Param parameter on incoming calls (see participant_id_param and + participant_id_header configuration in webconference.conf) implemented DI functions ------------------------ @@ -94,7 +107,7 @@ roomInfo(string room, string adminpin): ---- dialout(string room, string adminpin, string callee, string from_user, string domain, - string auth_user, string auth_pwd [, headers [, callee_domain]]) : + string auth_user, string auth_pwd [, headers [, callee_domain, [participant_id]]]) : int code, string result, string callid code/result: @@ -142,6 +155,10 @@ getRoomPassword(string master_pwd, string room) listRooms(string master_pwd) int code, string result ---- +findParticipant(string participant_id) + rooms: array of string + find all rooms a participant is in +----- additionally there is feedback functions to save call quality reports from users: vqRoomFeedback, vqCallFeedback, vqConferenceFeedback.