From e01a2ab430bae7db175904d24acce720bb8d182f Mon Sep 17 00:00:00 2001 From: hbeni Date: Wed, 5 May 2021 18:43:30 +0200 Subject: [PATCH] Change handling of PTT; add support for mumbles internal PTT binding PTT handling was moved from the UDP-Server to the mumble API callback mumble_onUserTalkingStateChanged(). The UDP COMn_PTT messages now just set a "request" bit in the affected radio. This is then evaluated in fgcom_handlePTT() to see if the plugin should activate the mumble requestMicrophoneActivationOvewrite() in order to open the mic. Wehn the mic opens (either by the override, or by mumbles own ptt binding, or by mumbles voice activation), the actual radio's ptt-state is calculated and (if changed) broadcast to remote clients. To know which radios should PTT by mumbles ptt/voiceact, the config file was enhanced: Configured radios will be set to PTT only when mumbles own activation was used, and not if just the protocol demand mic-opening by the override in fgcom_handlePTT(). This allows us easily to activate the mapping alongside any active protocol ptt-signals; the user thus can use both. Because of this, COM1 was activated as default in the config. (Resolves #110) --- README-de_DE.md | 2 + README.md | 2 + client/mumble-plugin/fgcom-mumble.cpp | 106 ++++++++++++++++++++-- client/mumble-plugin/fgcom-mumble.h | 4 +- client/mumble-plugin/fgcom-mumble.ini | 15 +++ client/mumble-plugin/lib/debug.cpp | 1 + client/mumble-plugin/lib/globalVars.h | 2 + client/mumble-plugin/lib/io_UDPServer.cpp | 28 +++--- client/mumble-plugin/lib/io_plugin.cpp | 43 ++++----- client/mumble-plugin/lib/radio_model.h | 4 +- client/plugin.spec.md | 1 + client/radioGUI/Readme.RadioGUI.md | 3 +- 12 files changed, 164 insertions(+), 47 deletions(-) diff --git a/README-de_DE.md b/README-de_DE.md index a0dd68a5..68609bb5 100644 --- a/README-de_DE.md +++ b/README-de_DE.md @@ -110,6 +110,8 @@ Bitte beachte, dass "Frequenzen" alles mögliche sein können. Dies bedeutet, da Dies sollte daher der kleinste gemeinsame Nenner sein, d.h. die physikalische Frequenz der Trägerwelle (vor allem mit 8.33kHz Kanälen, bei denen die im Gerät angewählte Frequenz nicht immer der physikalischen entspricht). Im Protokoll haben Fließkommazahlen außerdem immer den Punkt (`.`) als Dezimaltrenner; das Komma ist als Feldtrenner nicht erlaubt. +Obwohl wir davon ausgehen, dass die verbundenen Simulatoren Informationen für das PTT der Funkgeräte übermitteln, kannst du über die Konfigurationsdatei Zuordnungen für mumble's interne Sendeaktivierung definieren. Auf diese Weise kannst du beispielsweise mit mumbles eigenem PTT-Tastenkürzel das Senden deiner Funkgeräte aktivieren. Standardmäßig ist bereits das erste Funkgerät entsprechend konfiguriert, d.h. mumbles internes PTT aktiviert gleichzeitig das PTT des ersten Funkgerätes. + ### RadioGUI FGCom-mumble liefert eine plattformunabhängige Java-Applikation mit, die die meisten UDP-Protokollfelder implementiert. Dadurch eignet sich RadioGUI nicht nur zum testen, sondern auch für echte Aufgaben wie ATC ohne die Notwendigkeit eines weiteren Clients. diff --git a/README.md b/README.md index 46f75e8b..ff107d29 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,8 @@ The plugin aims to be compatible to the legacy fgcom-standalone protocol, so vey Note that frequencies can be arbitary strings. That said, all participating clients must share a common definition of "frequency", this should be the physical radio wave frequency in MHz and not the "channel" (esp. with 8.3 channels spacing). Also note that callsigns and frequencies are not allowed to contain the comma symbol (`,`). Decimal point symbol has always to be a point (`.`). +Despite we expect the connected simulator to provide PTT-information in order to activate radio transmissions, you may also use the configfile to define mappings for mumble's internal voice activation. This way, you can use mumbles own PTT-binding to activate the radios you mapped. By default, the first Radio is already mapped for your convinience. + ### RadioGUI FGCom-mumble releases ship with a cross-plattform java application that implements most of the UDP protocol and thus can be used not only for testing purposes, but also real operations without the need for another client. diff --git a/client/mumble-plugin/fgcom-mumble.cpp b/client/mumble-plugin/fgcom-mumble.cpp index 1fbaa847..bf7a0ded 100644 --- a/client/mumble-plugin/fgcom-mumble.cpp +++ b/client/mumble-plugin/fgcom-mumble.cpp @@ -124,14 +124,17 @@ bool fgcom_isPluginActive() { } /* - * Handle PTT change of local user - * + * Handle UDP protocol PTT-Request change of local user + * * This will check the local radio state and activate the mic if all is operable. * When no PTT or no radio is operable, mic is closed. + * + * Note: Opening the mic this way will trigger mumble_onUserTalkingStateChanged() which will + * calculate the to-be-synced PTT state to remotes. */ void fgcom_handlePTT() { if (fgcom_isPluginActive()) { - pluginDbg("Handling PTT state"); + pluginDbg("Handling PTT protocol request state"); // see which radio was used and if its operational. bool radio_serviceable, radio_powered, radio_switchedOn, radio_ptt; bool radio_ptt_result = false; // if we should open or close the mic, default no @@ -142,19 +145,19 @@ void fgcom_handlePTT() { fgcom_client lcl = lcl_idty.second; if (lcl.radios.size() > 0) { for (int i=0; i open mic"); + pluginDbg(" COM"+std::to_string(i+1)+" PTT_REQ active and radio is operable -> open mic"); radio_ptt_result = true; break; // we only have one output stream, so further search makes no sense } else { - pluginLog(" COM"+std::to_string(i+1)+" PTT active but radio not operable!"); + pluginLog(" COM"+std::to_string(i+1)+" PTT_REQ active but radio not operable!"); } } else { - pluginDbg(" COM"+std::to_string(i+1)+" PTT off"); + pluginDbg(" COM"+std::to_string(i+1)+" PTT_REQ off"); } } } @@ -168,7 +171,7 @@ void fgcom_handlePTT() { // Todo: do we need to reset something or so? i think no: // plugin deactivation will already handle setting the old transmission mode, // so the mic will be open according to that... - pluginDbg("Handling PTT state: PLUGIN NOT ACTIVE"); + pluginDbg("Handling PTT protocol request state: PLUGIN NOT ACTIVE"); } } @@ -297,12 +300,20 @@ mumble_error_t fgcom_loadConfig() { std::string token_value = sm[2]; pluginDbg("[CFG] Parsing token: "+token_key+"="+token_value); - if (token_key == "radioAudioEffects") fgcom_cfg.radioAudioEffects = (token_value == "0" || token_value == "false" || token_value == "off")? false : true; - if (token_key == "allowHearingNonPluginUsers") fgcom_cfg.allowHearingNonPluginUsers = (token_value == "1" || token_value == "true" || token_value == "on")? true : false; + if (token_key == "radioAudioEffects") fgcom_cfg.radioAudioEffects = (token_value == "0" || token_value == "false" || token_value == "off" || token_value == "no")? false : true; + if (token_key == "allowHearingNonPluginUsers") fgcom_cfg.allowHearingNonPluginUsers = (token_value == "1" || token_value == "true" || token_value == "on" || token_value == "yes")? true : false; if (token_key == "specialChannel") fgcom_cfg.specialChannel = token_value; if (token_key == "udpServerHost") fgcom_cfg.udpServerHost = token_value; if (token_key == "udpServerPort") fgcom_cfg.udpServerPort = std::stoi(token_value); if (token_key == "logfile") fgcom_cfg.logfile = token_value; + + std::smatch sm_m; + std::regex re_mblmap ("^mapMumblePTT(\\d+)$"); + if (std::regex_search(token_key, sm_m, re_mblmap)) { + int radio_id = std::stoi(sm_m[1]); + radio_id--; // convert to array index + fgcom_cfg.mapMumblePTT[radio_id] = (token_value == "1" || token_value == "true" || token_value == "on" || token_value == "yes")? true : false; + } } } } else { @@ -310,6 +321,18 @@ mumble_error_t fgcom_loadConfig() { } } + // Debug print final parsed config + pluginDbg("[CFG] final parsed config:"); + pluginDbg("[CFG] allowHearingNonPluginUsers="+std::to_string(fgcom_cfg.allowHearingNonPluginUsers)); + pluginDbg("[CFG] radioAudioEffects="+std::to_string(fgcom_cfg.radioAudioEffects)); + pluginDbg("[CFG] specialChannel="+fgcom_cfg.specialChannel); + pluginDbg("[CFG] udpServerHost="+fgcom_cfg.udpServerHost); + pluginDbg("[CFG] udpServerPort="+std::to_string(fgcom_cfg.udpServerPort)); + pluginDbg("[CFG] logfile="+fgcom_cfg.logfile); + for (const auto& cv : fgcom_cfg.mapMumblePTT) { + pluginDbg("[CFG] mapMumblePTT["+std::to_string(cv.first)+"]="+std::to_string(cv.second)); + } + return STATUS_OK; } @@ -769,6 +792,69 @@ void mumble_onChannelExited(mumble_connection_t connection, mumble_userid_t user } +// Called when any user changes his/her talking state. +// Handles the calculation of the PTT state that is sent to remotes. +void mumble_onUserTalkingStateChanged(mumble_connection_t connection, mumble_userid_t userID, mumble_talking_state_t talkingState) { + pluginDbg("User with ID "+ std::to_string(userID) + " changed talking state: " + std::to_string(talkingState) + ". (ServerConnection: " + std::to_string(connection) + ")"); + + if (userID == localMumId && fgcom_isPluginActive() ){ + // Current user is speaking. Either this activated trough the PTT button, or manually pushed mumble-ptt/voiceActivation + bool mumble_talk_detected = talkingState == TALKING || talkingState == WHISPERING || talkingState == SHOUTING; + + // look if there is some PTT_REQ set. + // If we have a PTT requested from the udp protocol, we are not activating the + // radios configured to respond to mumbles talk state change. + bool udp_protocol_ptt_detected = false; + for (const auto &lcl_idty : fgcom_local_client) { + int iid = lcl_idty.first; + fgcom_client lcl = lcl_idty.second; + if (lcl.radios.size() > 0) { + for (int radio_id=0; radio_id 0) { + for (int radio_id=0; radio_idsecond : false; + pluginDbg(" IID="+std::to_string(iid)+"; radio_id="+std::to_string(radio_id)+"; operable="+std::to_string(lcl.radios[radio_id].operable)); + pluginDbg(" radio_ptt_req="+std::to_string(radio_ptt_req)); + pluginDbg(" radio_mapmumbleptt="+std::to_string(radio_mapmumbleptt)); + for (const auto& cv : fgcom_cfg.mapMumblePTT) { + pluginDbg(" mapMumblePTT["+std::to_string(cv.first)+"]="+std::to_string(cv.second)); + } + + bool oldValue = fgcom_local_client[iid].radios[radio_id].ptt; + bool newValue = false; + pluginDbg(" old_ptt="+std::to_string(oldValue)); + pluginDbg(" mumble_talk_detected="+std::to_string(mumble_talk_detected)); + if ( radio_ptt_req || !udp_protocol_ptt_detected && radio_mapmumbleptt ) { + // We should activate/deactivate PTT on the radio; either it's ptt was pressed in the UDP client, or we are configured for honoring mumbles talk state + newValue = mumble_talk_detected && lcl.radios[radio_id].operable; + } + pluginDbg(" new_ptt="+std::to_string(lcl.radios[radio_id].ptt)); + + // broadcast changed PTT state to clients + fgcom_local_client[iid].radios[radio_id].ptt = newValue; + if (oldValue != newValue) { + pluginDbg(" COM"+std::to_string(radio_id+1)+" PTT changed: notifying remotes"); + notifyRemotes(iid, NTFY_COM, radio_id); + } + } + } + } + fgcom_localcfg_mtx.unlock(); + } +} // Note: Audio input is only possible with open mic. fgcom_hanldePTT() takes care of that. bool mumble_onAudioInput(short *inputPCM, uint32_t sampleCount, uint16_t channelCount, bool isSpeech) { diff --git a/client/mumble-plugin/fgcom-mumble.h b/client/mumble-plugin/fgcom-mumble.h index 40b507b6..42318481 100644 --- a/client/mumble-plugin/fgcom-mumble.h +++ b/client/mumble-plugin/fgcom-mumble.h @@ -23,8 +23,8 @@ // Plugin Version #define FGCOM_VERSION_MAJOR 0 -#define FGCOM_VERSION_MINOR 12 -#define FGCOM_VERSION_PATCH 1 +#define FGCOM_VERSION_MINOR 13 +#define FGCOM_VERSION_PATCH 0 /* * Is the plugin currently active? diff --git a/client/mumble-plugin/fgcom-mumble.ini b/client/mumble-plugin/fgcom-mumble.ini index f5e4994d..d359f312 100644 --- a/client/mumble-plugin/fgcom-mumble.ini +++ b/client/mumble-plugin/fgcom-mumble.ini @@ -38,6 +38,21 @@ ;allowHearingNonPluginUsers=0 +;; Use mumbles Talking state to activate PTT of your radios. +;; With this setting you can map mumbles talk-activation (mumble's ptt button or +;; voice activation) to your radio's virtual ptt buttons. Activation of mumbles ptt +;; will then also activate PTT on the configured radios. +;; +;; Note: Usually the connected client is expected to send COMn_PTT=1 packets to signify +;; that the PTT button of a specific radio was pressed. Some clients however +;; don't do that, which makes this mappings here the only way to signify PTT. +;; +;; You can define multiple mappings in the form mapMumblePTT{N}, where {N} is the +;; ID of the radio you want to map (eg. "mapMumblePTT1" maps COM1). +;mapMumblePTT1=1 +;mapMumblePTT2=0 + + ;; FGCom channel name(s) ;; The plugin will activate radio channel handling when inside this channel(s). ;; The parameter is a default ECMA regular expression (case ignore) and will match channel diff --git a/client/mumble-plugin/lib/debug.cpp b/client/mumble-plugin/lib/debug.cpp index cabd44eb..b2a52875 100644 --- a/client/mumble-plugin/lib/debug.cpp +++ b/client/mumble-plugin/lib/debug.cpp @@ -55,6 +55,7 @@ void debug_out_internal_state() { state_str += " Radio "+std::to_string(i)+": serviceable='"+std::to_string(lcl.radios[i].serviceable)+"'\n"; state_str += " Radio "+std::to_string(i)+": operable='"+std::to_string(lcl.radios[i].operable)+"'\n"; state_str += " Radio "+std::to_string(i)+": ptt='"+std::to_string(lcl.radios[i].ptt)+"'\n"; + state_str += " Radio "+std::to_string(i)+": ptt_req='"+std::to_string(lcl.radios[i].ptt_req)+"'\n"; state_str += " Radio "+std::to_string(i)+": volume='"+std::to_string(lcl.radios[i].volume)+"'\n"; state_str += " Radio "+std::to_string(i)+": pwr='"+std::to_string(lcl.radios[i].pwr)+"'\n"; state_str += " Radio "+std::to_string(i)+": squelch='"+std::to_string(lcl.radios[i].squelch)+"'\n"; diff --git a/client/mumble-plugin/lib/globalVars.h b/client/mumble-plugin/lib/globalVars.h index f7ce8b41..bc8ddec8 100644 --- a/client/mumble-plugin/lib/globalVars.h +++ b/client/mumble-plugin/lib/globalVars.h @@ -40,6 +40,7 @@ struct fgcom_config { std::string udpServerHost; int udpServerPort; std::string logfile; + std::map mapMumblePTT; // which radios to activate when mumble-internal talk activation is used fgcom_config() { allowHearingNonPluginUsers = false; @@ -48,6 +49,7 @@ struct fgcom_config { udpServerHost = "127.0.0.1"; udpServerPort = 16661; logfile = ""; + mapMumblePTT = {{0,true}}; }; }; extern struct fgcom_config fgcom_cfg; diff --git a/client/mumble-plugin/lib/io_UDPServer.cpp b/client/mumble-plugin/lib/io_UDPServer.cpp index ba813056..8b1a70c0 100644 --- a/client/mumble-plugin/lib/io_UDPServer.cpp +++ b/client/mumble-plugin/lib/io_UDPServer.cpp @@ -292,9 +292,9 @@ std::map fgcom_udp_parseMsg(char buffer[MAXLINE] if (parsedPTT && fgcom_com_ptt_compatmode) fgcom_com_ptt_compatmode = false; if (!fgcom_com_ptt_compatmode) { - bool oldValue = fgcom_local_client[iid].radios[radio_id].ptt; - fgcom_local_client[iid].radios[radio_id].ptt = parsedPTT; - if (fgcom_local_client[iid].radios[radio_id].ptt != oldValue ) parseResult[iid].radioData.insert(radio_id); + bool oldValue = fgcom_local_client[iid].radios[radio_id].ptt_req; + fgcom_local_client[iid].radios[radio_id].ptt_req = parsedPTT; + //if (fgcom_local_client[iid].radios[radio_id].ptt_req != oldValue ) parseResult[iid].radioData.insert(radio_id); needToHandlePTT = true; } @@ -338,6 +338,10 @@ std::map fgcom_udp_parseMsg(char buffer[MAXLINE] fgcom_local_client[iid].radios[radio_id].publish = (token_value == "1" || token_value == "true")? true : false; // must never be sended - it's a local config property } + if (radio_var == "MAPMUMBLEPTT") { + fgcom_cfg.mapMumblePTT[radio_id] = (token_value == "1" || token_value == "true" || token_value == "on" || token_value == "yes")? true : false; + // must never be sended - it's a local config property + } } @@ -385,18 +389,18 @@ std::map fgcom_udp_parseMsg(char buffer[MAXLINE] if (ptt_id > 0) fgcom_com_ptt_compatmode = true; if (fgcom_com_ptt_compatmode) { - pluginDbg("DBG_PTT: ptt_id="+std::to_string(ptt_id)); + //pluginDbg("DBG_PTT: ptt_id="+std::to_string(ptt_id)); for (int i = 0; i::iterator it=ures.radioData.begin(); it!=ures.radioData.end(); ++it) { // iterate trough changed radio instances //std::cout << "ITERATOR: " << ' ' << *it; - pluginDbg("FGCom: [UDP-server] radioData for iid='"+std::to_string(iid)+"', radio_id="+std::to_string(*it)+" has changed, notifying other clients"); + pluginDbg("[UDP-server] radioData for iid='"+std::to_string(iid)+"', radio_id="+std::to_string(*it)+" has changed, notifying other clients"); notifyRemotes(iid, NTFY_COM, *it); fgcom_updateClientComment(); } diff --git a/client/mumble-plugin/lib/io_plugin.cpp b/client/mumble-plugin/lib/io_plugin.cpp index 02820b10..57367b2a 100644 --- a/client/mumble-plugin/lib/io_plugin.cpp +++ b/client/mumble-plugin/lib/io_plugin.cpp @@ -143,17 +143,17 @@ void notifyRemotes(int iid, FGCOM_NOTIFY_T what, int selector, mumble_userid_t t std::string message(""); // the message as sting data (yeah, i'm lazy but it parses so easily and is human readable and therefore easy to debug) // check if we are connected and synchronized - pluginDbg("notifyRemotes("+std::to_string(iid)+","+std::to_string(what)+","+std::to_string(selector)+","+std::to_string(tgtUser)+") called"); + pluginDbg("[mum_pluginIO] notifyRemotes("+std::to_string(iid)+","+std::to_string(what)+","+std::to_string(selector)+","+std::to_string(tgtUser)+") called"); if (!fgcom_isConnectedToServer()) { - pluginDbg("notifyRemotes(): not connected, so not notifying."); + pluginDbg("[mum_pluginIO] notifyRemotes(): not connected, so not notifying."); return; } else { - pluginDbg("notifyRemotes(): we are connected, so notifications will be sent."); + pluginDbg("[mum_pluginIO] notifyRemotes(): we are connected, so notifications will be sent."); } // If all identities are selected, invoke notifyRemotes() for each of them if (iid == NTFY_ALL) { - pluginDbg("notifyRemotes(): identities: all selected, resolving..."); + pluginDbg("[mum_pluginIO] notifyRemotes(): identities: all selected, resolving..."); for (const auto &idty : fgcom_local_client) { notifyRemotes(idty.first, what, selector, tgtUser); } @@ -161,7 +161,7 @@ void notifyRemotes(int iid, FGCOM_NOTIFY_T what, int selector, mumble_userid_t t } else { // skip notification attempts if we don't have any local state yet if (fgcom_local_client.size() == 0 ) { - pluginDbg("notifyRemotes(): no local state yet, skipping notifications."); + pluginDbg("[mum_pluginIO] notifyRemotes(): no local state yet, skipping notifications."); return; } } @@ -170,9 +170,9 @@ void notifyRemotes(int iid, FGCOM_NOTIFY_T what, int selector, mumble_userid_t t fgcom_client lcl; if (fgcom_local_client.count(iid) > 0) { lcl = fgcom_local_client[iid]; - pluginDbg("notifyRemotes(): successfully resolved identity='"+std::to_string(iid)+"' (callsign="+lcl.callsign+")"); + pluginDbg("[mum_pluginIO] notifyRemotes(): successfully resolved identity='"+std::to_string(iid)+"' (callsign="+lcl.callsign+")"); } else { - pluginLog("notifyRemotes(): ERROR resolving identity='"+std::to_string(iid)+"'!"); + pluginLog("[mum_pluginIO] notifyRemotes(): ERROR resolving identity='"+std::to_string(iid)+"'!"); return; } @@ -182,7 +182,7 @@ void notifyRemotes(int iid, FGCOM_NOTIFY_T what, int selector, mumble_userid_t t switch (what) { case NTFY_ALL: // notify all info - pluginDbg("notifyRemotes(): selected: all"); + pluginDbg("[mum_pluginIO] notifyRemotes(): selected: all"); notifyRemotes(iid, NTFY_USR, NTFY_ALL, tgtUser); // userdata notifyRemotes(iid, NTFY_LOC, NTFY_ALL, tgtUser); // location notifyRemotes(iid, NTFY_COM, NTFY_ALL, tgtUser); // radios @@ -190,7 +190,7 @@ void notifyRemotes(int iid, FGCOM_NOTIFY_T what, int selector, mumble_userid_t t case NTFY_LOC: // Notify on location - pluginDbg("notifyRemotes(): selected: location"); + pluginDbg("[mum_pluginIO] notifyRemotes(): selected: location"); dataID = "FGCOM:UPD_LOC:"+std::to_string(iid); message = "LAT="+std::to_string(lcl.lat)+"," +"LON="+std::to_string(lcl.lon)+"," @@ -199,15 +199,15 @@ void notifyRemotes(int iid, FGCOM_NOTIFY_T what, int selector, mumble_userid_t t case NTFY_COM: // notify on radio state - pluginDbg("notifyRemotes(): selected radio"); + pluginDbg("[mum_pluginIO] notifyRemotes(): selected radio"); if (selector == NTFY_ALL) { - pluginDbg("notifyRemotes(): all radios selected"); + pluginDbg("[mum_pluginIO] notifyRemotes(): all radios selected"); for (int ri=0; ri < lcl.radios.size(); ri++) { notifyRemotes(iid, NTFY_COM, ri, tgtUser); } } else { if (lcl.radios[selector].publish) { - pluginDbg("notifyRemotes(): send state of COM"+std::to_string(selector+1) ); + pluginDbg("[mum_pluginIO] notifyRemotes(): send state of COM"+std::to_string(selector+1) ); dataID = "FGCOM:UPD_COM:"+std::to_string(iid)+":"+std::to_string(selector); message = "FRQ="+lcl.radios[selector].frequency+"," + "CHN="+lcl.radios[selector].dialedFRQ+"," @@ -236,7 +236,7 @@ void notifyRemotes(int iid, FGCOM_NOTIFY_T what, int selector, mumble_userid_t t case NTFY_USR: // userstate - pluginDbg("notifyRemotes(): selected: userdata"); + pluginDbg("[mum_pluginIO] notifyRemotes(): selected: userdata"); dataID = "FGCOM:UPD_USR:"+std::to_string(iid); message = "CALLSIGN="+lcl.callsign; break; @@ -252,7 +252,7 @@ void notifyRemotes(int iid, FGCOM_NOTIFY_T what, int selector, mumble_userid_t t break; default: - pluginDbg("notifyRemotes("+std::to_string(iid)+","+std::to_string(what)+","+std::to_string(selector)+","+std::to_string(tgtUser)+"): 'what' unknown"); + pluginDbg("[mum_pluginIO] notifyRemotes("+std::to_string(iid)+","+std::to_string(what)+","+std::to_string(selector)+","+std::to_string(tgtUser)+"): 'what' unknown"); return; } @@ -263,12 +263,12 @@ void notifyRemotes(int iid, FGCOM_NOTIFY_T what, int selector, mumble_userid_t t mumble_userid_t *userIDs; mumble_channelid_t localChannelID; if (mumAPI.getChannelOfUser(ownPluginID, activeConnection, localMumId, &localChannelID) != STATUS_OK) { - pluginLog("[ERROR]: Can't obtain channel of local user"); + pluginLog("[mum_pluginIO] [ERROR]: Can't obtain channel of local user"); return; } if (mumAPI.getUsersInChannel(ownPluginID, activeConnection, localChannelID, &userIDs, &userCount) != STATUS_OK) { - pluginLog("[ERROR]: Can't obtain user list"); + pluginLog("[mum_pluginIO] [ERROR]: Can't obtain user list"); return; } else { pluginDbg("There are "+std::to_string(userCount)+" users on this channel."); @@ -313,7 +313,8 @@ void notifyRemotes(int iid, FGCOM_NOTIFY_T what, int selector, mumble_userid_t t } mumAPI.freeMemory(ownPluginID, userIDs); - pluginDbg(" notification for dataID='"+dataID+"' done."); + pluginDbg("[mum_pluginIO] message was: '"+message+"'"); + pluginDbg("[mum_pluginIO] notification for dataID='"+dataID+"' done."); } } @@ -397,7 +398,7 @@ bool handlePluginDataReceived(mumble_userid_t senderID, std::string dataID, std: // Userdata and Location data update are treated the same } else if (dataID == "FGCOM:UPD_USR:"+iid_str || dataID == "FGCOM:UPD_LOC:"+iid_str) { - pluginDbg("USR/LOC UPDATE: Sender="+std::to_string(clientID)+" DataID="+dataID+" DATA="+data); + pluginDbg("[mum_pluginIO] USR/LOC UPDATE: Sender="+std::to_string(clientID)+" DataID="+dataID+" DATA="+data); // update properties std::stringstream streambuffer(data); @@ -419,7 +420,7 @@ bool handlePluginDataReceived(mumble_userid_t senderID, std::string dataID, std: int curlength = token_value.length(); if (curlength > MAX_PLUGINIO_FIELDLENGTH) { token_value = token_value.substr(0, MAX_PLUGINIO_FIELDLENGTH); - pluginLog("[UDP-server] WARNING: supplied token "+token_key+" length="+std::to_string(curlength)+" is greater than allowed "+std::to_string(MAX_PLUGINIO_FIELDLENGTH)+": Field truncated!"); + pluginLog("[mum_pluginIO] WARNING: supplied token "+token_key+" length="+std::to_string(curlength)+" is greater than allowed "+std::to_string(MAX_PLUGINIO_FIELDLENGTH)+": Field truncated!"); } // Location data @@ -443,7 +444,7 @@ bool handlePluginDataReceived(mumble_userid_t senderID, std::string dataID, std: } else if (dataID.substr(0, 15+iid_str.length()) == "FGCOM:UPD_COM:"+iid_str+":") { // Radio data update. Here the radio in question was given in the dataid. - pluginDbg("COM UPDATE: Sender="+std::to_string(clientID)+" DataID="+dataID+" DATA="+data); + pluginDbg("[mum_pluginIO] COM UPDATE: Sender="+std::to_string(clientID)+" DataID="+dataID+" DATA="+data); int radio_id = std::stoi(dataID.substr(15+iid_str.length())); // when segfault: indicates problem with the implemented udp protocol // if the selected radio does't exist, create it now @@ -473,7 +474,7 @@ bool handlePluginDataReceived(mumble_userid_t senderID, std::string dataID, std: int curlength = token_value.length(); if (curlength > MAX_PLUGINIO_FIELDLENGTH) { token_value = token_value.substr(0, MAX_PLUGINIO_FIELDLENGTH); - pluginLog("[UDP-server] WARNING: supplied token "+token_key+" length="+std::to_string(curlength)+" is greater than allowed "+std::to_string(MAX_PLUGINIO_FIELDLENGTH)+": Field truncated!"); + pluginLog("[mum_pluginIO] WARNING: supplied token "+token_key+" length="+std::to_string(curlength)+" is greater than allowed "+std::to_string(MAX_PLUGINIO_FIELDLENGTH)+": Field truncated!"); } if (token_key == "FRQ") { diff --git a/client/mumble-plugin/lib/radio_model.h b/client/mumble-plugin/lib/radio_model.h index 56bf6af0..2f6fd21e 100644 --- a/client/mumble-plugin/lib/radio_model.h +++ b/client/mumble-plugin/lib/radio_model.h @@ -38,7 +38,8 @@ struct fgcom_radio { bool power_btn; // true if switched on float volts; // how much electric power it has (>0 = on) bool serviceable; // false if broken - bool ptt; // true if PTT is pushed + bool ptt; // true if PTT is actually pushed (synced to remotes and used to determine reception) + bool ptt_req; // true if PTT is requested from client/udp float volume; // volume, 0.0->1.0 float pwr; // tx power in watts bool operable; // false if switched off, not powered or broken @@ -54,6 +55,7 @@ struct fgcom_radio { volts = 12; serviceable = true; ptt = false; + ptt_req = false; volume = 1.0; pwr = 10; operable = true; diff --git a/client/plugin.spec.md b/client/plugin.spec.md index 14b2da77..a6f122a5 100644 --- a/client/plugin.spec.md +++ b/client/plugin.spec.md @@ -121,6 +121,7 @@ The Following fields are configuration options that change plugin behaviour. | `COM`*n*`_PUBLISH`| Bool | Set to `0` to prevent this radio from being published anymore. Use this at the first the radio field! | `1`| | `AUDIO_FX_RADIO` | Bool | `0` will switch radio effects like static off. | `1` | | `AUDIO_HEAR_ALL` | Bool | `1` will enable hearing of non-plugin users. | `0` | +| `COM`*n*`_MAPMUMBLEPTT` | Bool | `1` switches PTT handling to mumbles own talking state and activates _this_ radios PTT when mumble activates talking.| COM1=`1`, others=`0` | ### Testing UDP input diff --git a/client/radioGUI/Readme.RadioGUI.md b/client/radioGUI/Readme.RadioGUI.md index 29bcb202..a31bbb4f 100644 --- a/client/radioGUI/Readme.RadioGUI.md +++ b/client/radioGUI/Readme.RadioGUI.md @@ -41,7 +41,8 @@ For doing so, you must enable the connection in the simulator. ``` -Then you can adjust the SimConnect options in RadioGUI's Options-dialog and finally activate it by choosing the respective option from RadioGUI's main menu. +Then you can adjust the SimConnect options in RadioGUI's Options-dialog and finally activate it by choosing the respective option from RadioGUI's main menu. +Per default, the FGCom-mumble plugin does map mumbles talk activation to COM1-PTT, so you can use mumbles PTT binding to activate COM1 transmissions transparently. Compiling