Merge pull request #9052 from davidkelly/dk/2226

Add ability to mute user
This commit is contained in:
Chris Collins 2016-11-11 16:02:08 -08:00 committed by GitHub
commit 6581a51bc9
12 changed files with 152 additions and 21 deletions

View file

@ -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()

View file

@ -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);

View file

@ -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

View file

@ -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()) {

View file

@ -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.";
}
}

View file

@ -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();

View file

@ -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

View file

@ -99,7 +99,8 @@ public:
SelectedAudioFormat,
MoreEntityShapes,
NodeKickRequest,
LAST_PACKET_TYPE = NodeKickRequest
NodeMuteRequest,
LAST_PACKET_TYPE = NodeMuteRequest
};
};

View file

@ -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();

View file

@ -28,6 +28,7 @@ public:
public slots:
void ignore(const QUuid& nodeID);
void kick(const QUuid& nodeID);
void mute(const QUuid& nodeID);
bool getCanKick();

View 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

View file

@ -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);
}
}
}