mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #9052 from davidkelly/dk/2226
Add ability to mute user
This commit is contained in:
commit
6581a51bc9
12 changed files with 152 additions and 21 deletions
|
@ -94,7 +94,8 @@ AudioMixer::AudioMixer(ReceivedMessage& message) :
|
|||
packetReceiver.registerListener(PacketType::MuteEnvironment, this, "handleMuteEnvironmentPacket");
|
||||
packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket");
|
||||
packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket");
|
||||
|
||||
packetReceiver.registerListener(PacketType::NodeMuteRequest, this, "handleNodeMuteRequestPacket");
|
||||
|
||||
connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled);
|
||||
}
|
||||
|
||||
|
@ -599,6 +600,23 @@ void AudioMixer::handleNodeKilled(SharedNodePointer killedNode) {
|
|||
});
|
||||
}
|
||||
|
||||
void AudioMixer::handleNodeMuteRequestPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QUuid nodeUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||
if (sendingNode->getCanKick()) {
|
||||
auto node = nodeList->nodeWithUUID(nodeUUID);
|
||||
if (node) {
|
||||
// we need to set a flag so we send them the appropriate packet to mute them
|
||||
AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData();
|
||||
nodeData->setShouldMuteClient(true);
|
||||
} else {
|
||||
qWarning() << "Node mute packet received for unknown node " << uuidStringWithoutCurlyBraces(nodeUUID);
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Node mute packet received from node that cannot mute, ignoring";
|
||||
}
|
||||
}
|
||||
|
||||
void AudioMixer::handleKillAvatarPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode) {
|
||||
auto clientData = dynamic_cast<AudioMixerClientData*>(sendingNode->getLinkedData());
|
||||
if (clientData) {
|
||||
|
@ -814,9 +832,13 @@ void AudioMixer::broadcastMixes() {
|
|||
|
||||
// if the stream should be muted, send mute packet
|
||||
if (nodeData->getAvatarAudioStream()
|
||||
&& shouldMute(nodeData->getAvatarAudioStream()->getQuietestFrameLoudness())) {
|
||||
&& (shouldMute(nodeData->getAvatarAudioStream()->getQuietestFrameLoudness())
|
||||
|| nodeData->shouldMuteClient())) {
|
||||
auto mutePacket = NLPacket::create(PacketType::NoisyMute, 0);
|
||||
nodeList->sendPacket(std::move(mutePacket), *node);
|
||||
|
||||
// probably now we just reset the flag, once should do it (?)
|
||||
nodeData->setShouldMuteClient(false);
|
||||
}
|
||||
|
||||
if (node->getType() == NodeType::Agent && node->getActiveSocket()
|
||||
|
|
|
@ -49,6 +49,7 @@ private slots:
|
|||
void handleNodeKilled(SharedNodePointer killedNode);
|
||||
void handleNodeIgnoreRequestPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
||||
void handleKillAvatarPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
||||
void handleNodeMuteRequestPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
||||
|
||||
void removeHRTFsForFinishedInjector(const QUuid& streamID);
|
||||
|
||||
|
|
|
@ -86,6 +86,9 @@ public:
|
|||
bool shouldFlushEncoder() { return _shouldFlushEncoder; }
|
||||
|
||||
QString getCodecName() { return _selectedCodecName; }
|
||||
|
||||
bool shouldMuteClient() { return _shouldMuteClient; }
|
||||
void setShouldMuteClient(bool shouldMuteClient) { _shouldMuteClient = shouldMuteClient; }
|
||||
|
||||
signals:
|
||||
void injectorStreamFinished(const QUuid& streamIdentifier);
|
||||
|
@ -114,6 +117,8 @@ private:
|
|||
Decoder* _decoder{ nullptr }; // for mic stream
|
||||
|
||||
bool _shouldFlushEncoder { false };
|
||||
|
||||
bool _shouldMuteClient { false };
|
||||
};
|
||||
|
||||
#endif // hifi_AudioMixerClientData_h
|
||||
|
|
|
@ -634,7 +634,6 @@ bool DomainServerSettingsManager::ensurePermissionsForGroupRanks() {
|
|||
return changed;
|
||||
}
|
||||
|
||||
|
||||
void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
||||
// before we do any processing on this packet make sure it comes from a node that is allowed to kick
|
||||
if (sendingNode->getCanKick()) {
|
||||
|
|
|
@ -815,3 +815,31 @@ void NodeList::kickNodeBySessionID(const QUuid& nodeID) {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
void NodeList::muteNodeBySessionID(const QUuid& nodeID) {
|
||||
// cannot mute yourself, or nobody
|
||||
if (!nodeID.isNull() && _sessionUUID != nodeID ) {
|
||||
if (getThisNodeCanKick()) {
|
||||
auto audioMixer = soloNodeOfType(NodeType::AudioMixer);
|
||||
if (audioMixer) {
|
||||
// setup the packet
|
||||
auto mutePacket = NLPacket::create(PacketType::NodeMuteRequest, NUM_BYTES_RFC4122_UUID, true);
|
||||
|
||||
// write the node ID to the packet
|
||||
mutePacket->write(nodeID.toRfc4122());
|
||||
|
||||
qDebug() << "Sending packet to mute node" << uuidStringWithoutCurlyBraces(nodeID);
|
||||
|
||||
sendPacket(std::move(mutePacket), *audioMixer);
|
||||
} else {
|
||||
qWarning() << "Couldn't find audio mixer to send node mute request";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "You do not have permissions to mute in this domain."
|
||||
<< "Request to mute node" << uuidStringWithoutCurlyBraces(nodeID) << "will not be sent";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "NodeList::muteNodeBySessionID called with an invalid ID or an ID which matches the current session ID.";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
bool isIgnoringNode(const QUuid& nodeID) const;
|
||||
|
||||
void kickNodeBySessionID(const QUuid& nodeID);
|
||||
void muteNodeBySessionID(const QUuid& nodeID);
|
||||
|
||||
public slots:
|
||||
void reset();
|
||||
|
|
|
@ -26,7 +26,8 @@ const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
|
|||
<< PacketType::NodeJsonStats << PacketType::EntityQuery
|
||||
<< PacketType::OctreeDataNack << PacketType::EntityEditNack
|
||||
<< PacketType::DomainListRequest << PacketType::StopNode
|
||||
<< PacketType::DomainDisconnectRequest << PacketType::NodeKickRequest;
|
||||
<< PacketType::DomainDisconnectRequest << PacketType::NodeKickRequest
|
||||
<< PacketType::NodeMuteRequest;
|
||||
|
||||
const QSet<PacketType> NON_SOURCED_PACKETS = QSet<PacketType>()
|
||||
<< PacketType::StunResponse << PacketType::CreateAssignment << PacketType::RequestAssignment
|
||||
|
|
|
@ -99,7 +99,8 @@ public:
|
|||
SelectedAudioFormat,
|
||||
MoreEntityShapes,
|
||||
NodeKickRequest,
|
||||
LAST_PACKET_TYPE = NodeKickRequest
|
||||
NodeMuteRequest,
|
||||
LAST_PACKET_TYPE = NodeMuteRequest
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,11 @@ void UsersScriptingInterface::kick(const QUuid& nodeID) {
|
|||
DependencyManager::get<NodeList>()->kickNodeBySessionID(nodeID);
|
||||
}
|
||||
|
||||
void UsersScriptingInterface::mute(const QUuid& nodeID) {
|
||||
// ask the NodeList to mute the user with the given session ID
|
||||
DependencyManager::get<NodeList>()->muteNodeBySessionID(nodeID);
|
||||
}
|
||||
|
||||
bool UsersScriptingInterface::getCanKick() {
|
||||
// ask the NodeList to return our ability to kick
|
||||
return DependencyManager::get<NodeList>()->getThisNodeCanKick();
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
public slots:
|
||||
void ignore(const QUuid& nodeID);
|
||||
void kick(const QUuid& nodeID);
|
||||
void mute(const QUuid& nodeID);
|
||||
|
||||
bool getCanKick();
|
||||
|
||||
|
|
33
scripts/system/assets/images/mute-target.svg
Executable file
33
scripts/system/assets/images/mute-target.svg
Executable file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 293 101.9" style="enable-background:new 0 0 293 101.9;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#EF3B4E;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path d="M16.2,23.2H283c3.9,0,7.1,3.2,7.1,7.1V88c0,3.9-3.2,7.1-7.1,7.1H16.2c-3.9,0-7.1-3.2-7.1-7.1V30.3
|
||||
C9.1,26.4,12.3,23.2,16.2,23.2z"/>
|
||||
<path class="st0" d="M13.9,20.3h266.8c3.9,0,7.1,3.2,7.1,7.1v57.7c0,3.9-3.2,7.1-7.1,7.1H13.9c-3.9,0-7.1-3.2-7.1-7.1V27.4
|
||||
C6.8,23.5,10,20.3,13.9,20.3z"/>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M103.4,79.8V52.4L92.8,72.8h-4.4L77.7,52.4v27.4h-8.1V38.3h8.6l12.3,23.6l12.4-23.6h8.6v41.5H103.4z"/>
|
||||
<path d="M137.6,73c1.9,0,3.5-0.4,4.8-1.2c1.3-0.8,2.4-1.8,3.2-3c0.8-1.2,1.4-2.7,1.7-4.3c0.3-1.6,0.5-3.3,0.5-5V38.3h8v21.1
|
||||
c0,2.8-0.3,5.5-1,8c-0.7,2.5-1.8,4.7-3.2,6.5c-1.5,1.9-3.3,3.3-5.6,4.4c-2.3,1.1-5,1.6-8.2,1.6c-3.3,0-6.1-0.6-8.4-1.7
|
||||
c-2.3-1.1-4.2-2.7-5.6-4.6c-1.4-1.9-2.5-4.1-3.1-6.6c-0.6-2.5-1-5.1-1-7.8V38.3h8.1v21.1c0,1.8,0.2,3.4,0.5,5.1
|
||||
c0.3,1.6,0.9,3,1.7,4.3c0.8,1.2,1.8,2.2,3.1,3C134.2,72.6,135.7,73,137.6,73z"/>
|
||||
<path d="M194.8,45.4h-13.2v34.4h-8.1V45.4h-13.3v-7.1h34.5V45.4z"/>
|
||||
<path d="M228.8,72.7v7.1H200V38.3h28.3v7.1h-20.2v10h17.5v6.5h-17.5v10.8H228.8z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M101.5,77.9V50.4L90.8,70.9h-4.4L75.7,50.4v27.4h-8.1V36.4h8.6L88.6,60L101,36.4h8.6v41.5H101.5z"/>
|
||||
<path class="st1" d="M135.7,71c1.9,0,3.5-0.4,4.8-1.2c1.3-0.8,2.4-1.8,3.2-3c0.8-1.2,1.4-2.7,1.7-4.3c0.3-1.6,0.5-3.3,0.5-5V36.4
|
||||
h8v21.1c0,2.8-0.3,5.5-1,8c-0.7,2.5-1.8,4.7-3.2,6.5c-1.5,1.9-3.3,3.3-5.6,4.4c-2.3,1.1-5,1.6-8.2,1.6c-3.3,0-6.1-0.6-8.4-1.7
|
||||
c-2.3-1.1-4.2-2.7-5.6-4.6c-1.4-1.9-2.5-4.1-3.1-6.6c-0.6-2.5-1-5.1-1-7.8V36.4h8.1v21.1c0,1.8,0.2,3.4,0.5,5.1
|
||||
c0.3,1.6,0.9,3,1.7,4.3c0.8,1.2,1.8,2.2,3.1,3C132.2,70.6,133.8,71,135.7,71z"/>
|
||||
<path class="st1" d="M192.9,43.5h-13.2v34.4h-8.1V43.5h-13.3v-7.1h34.5V43.5z"/>
|
||||
<path class="st1" d="M226.9,70.8v7.1h-28.8V36.4h28.3v7.1h-20.2v10h17.5V60h-17.5v10.8H226.9z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -52,7 +52,9 @@ function removeOverlays() {
|
|||
|
||||
for (var i = 0; i < modOverlayKeys.length; ++i) {
|
||||
var avatarID = modOverlayKeys[i];
|
||||
Overlays.deleteOverlay(modOverlays[avatarID]);
|
||||
for (var j = 0; j < modOverlays[avatarID].length; ++j) {
|
||||
Overlays.deleteOverlay(modOverlays[avatarID][j]);
|
||||
}
|
||||
}
|
||||
|
||||
modOverlays = {};
|
||||
|
@ -74,10 +76,14 @@ function buttonClicked(){
|
|||
|
||||
button.clicked.connect(buttonClicked);
|
||||
|
||||
function overlayURL() {
|
||||
function kickOverlayURL() {
|
||||
return ASSETS_PATH + "/images/" + (Users.canKick ? "kick-target.svg" : "ignore-target.svg");
|
||||
}
|
||||
|
||||
function muteOverlayURL() {
|
||||
return ASSETS_PATH + "/images/" + "mute-target.svg";
|
||||
}
|
||||
|
||||
function updateOverlays() {
|
||||
if (isShowingOverlays) {
|
||||
|
||||
|
@ -101,20 +107,28 @@ function updateOverlays() {
|
|||
}
|
||||
|
||||
// setup a position for the overlay that is just above this avatar's head
|
||||
var overlayPosition = avatar.getJointPosition("Head");
|
||||
overlayPosition.y += 0.45;
|
||||
var kickOverlayPosition = avatar.getJointPosition("Head");
|
||||
kickOverlayPosition.y += 0.45;
|
||||
var muteOverlayPosition = avatar.getJointPosition("Head");
|
||||
muteOverlayPosition.y += 0.70;
|
||||
|
||||
if (avatarID in modOverlays) {
|
||||
// keep the overlay above the current position of this avatar
|
||||
Overlays.editOverlay(modOverlays[avatarID], {
|
||||
position: overlayPosition,
|
||||
url: overlayURL()
|
||||
Overlays.editOverlay(modOverlays[avatarID][0], {
|
||||
position: kickOverlayPosition,
|
||||
url: kickOverlayURL()
|
||||
});
|
||||
if (Users.canKick) {
|
||||
Overlays.editOverlay(modOverlays[avatarID][1], {
|
||||
position: muteOverlayPosition,
|
||||
url: muteOverlayURL()
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// add the overlay above this avatar
|
||||
var newOverlay = Overlays.addOverlay("image3d", {
|
||||
url: overlayURL(),
|
||||
position: overlayPosition,
|
||||
var newKickOverlay = Overlays.addOverlay("image3d", {
|
||||
url: kickOverlayURL(),
|
||||
position: kickOverlayPosition,
|
||||
size: 1,
|
||||
scale: 0.4,
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
|
@ -123,9 +137,24 @@ function updateOverlays() {
|
|||
isFacingAvatar: true,
|
||||
drawInFront: true
|
||||
});
|
||||
|
||||
// push this overlay to our array of overlays
|
||||
modOverlays[avatarID] = newOverlay;
|
||||
|
||||
modOverlays[avatarID]=[newKickOverlay];
|
||||
|
||||
if (Users.canKick) {
|
||||
var newMuteOverlay = Overlays.addOverlay("image3d", {
|
||||
url: muteOverlayURL(),
|
||||
position: muteOverlayPosition,
|
||||
size: 1,
|
||||
scale: 0.4,
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
alpha: 1,
|
||||
solid: true,
|
||||
isFacingAvatar: true,
|
||||
drawInFront: true
|
||||
});
|
||||
// push this overlay to our array of overlays
|
||||
modOverlays[avatarID].push(newMuteOverlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +167,9 @@ AvatarList.avatarRemovedEvent.connect(function(avatarID){
|
|||
// we are currently showing overlays and an avatar just went away
|
||||
|
||||
// first remove the rendered overlay
|
||||
Overlays.deleteOverlay(modOverlays[avatarID]);
|
||||
for (var overlay in modOverlays[avatarID]) {
|
||||
Overlays.deleteOverlay(overlay);
|
||||
}
|
||||
|
||||
// delete the saved ID of the overlay from our mod overlays object
|
||||
delete modOverlays[avatarID];
|
||||
|
@ -151,7 +182,8 @@ function handleSelectedOverlay(clickedOverlay) {
|
|||
var modOverlayKeys = Object.keys(modOverlays);
|
||||
for (var i = 0; i < modOverlayKeys.length; ++i) {
|
||||
var avatarID = modOverlayKeys[i];
|
||||
var modOverlay = modOverlays[avatarID];
|
||||
var modOverlay = modOverlays[avatarID][0];
|
||||
var muteOverlay = modOverlays[avatarID][1];
|
||||
|
||||
if (clickedOverlay.overlayID == modOverlay) {
|
||||
// matched to an overlay, ask for the matching avatar to be kicked or ignored
|
||||
|
@ -160,8 +192,10 @@ function handleSelectedOverlay(clickedOverlay) {
|
|||
} else {
|
||||
Users.ignore(avatarID);
|
||||
}
|
||||
|
||||
// cleanup of the overlay is handled by the connection to avatarRemovedEvent
|
||||
|
||||
} else if (muteOverlay && clickedOverlay.overlayID == muteOverlay) {
|
||||
Users.mute(avatarID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue