aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llvoiceclient.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-09-06 18:24:57 -0500
committerJacek Antonelli2008-09-06 18:25:07 -0500
commit798d367d54a6c6379ad355bd8345fa40e31e7fe9 (patch)
tree1921f1708cd0240648c97bc02df2c2ab5f2fc41e /linden/indra/newview/llvoiceclient.cpp
parentSecond Life viewer sources 1.20.15 (diff)
downloadmeta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.zip
meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.gz
meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.bz2
meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.xz
Second Life viewer sources 1.21.0-RC
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llvoiceclient.cpp177
1 files changed, 124 insertions, 53 deletions
diff --git a/linden/indra/newview/llvoiceclient.cpp b/linden/indra/newview/llvoiceclient.cpp
index 7f63aca..bedf1d9 100644
--- a/linden/indra/newview/llvoiceclient.cpp
+++ b/linden/indra/newview/llvoiceclient.cpp
@@ -1,4 +1,4 @@
1/** 1 /**
2 * @file llvoiceclient.cpp 2 * @file llvoiceclient.cpp
3 * @brief Implementation of LLVoiceClient class which is the interface to the voice client process. 3 * @brief Implementation of LLVoiceClient class which is the interface to the voice client process.
4 * 4 *
@@ -39,7 +39,11 @@
39#include "llvoavatar.h" 39#include "llvoavatar.h"
40#include "llbufferstream.h" 40#include "llbufferstream.h"
41#include "llfile.h" 41#include "llfile.h"
42#include "expat/expat.h" 42#ifdef LL_STANDALONE
43# include "expat.h"
44#else
45# include "expat/expat.h"
46#endif
43#include "llcallbacklist.h" 47#include "llcallbacklist.h"
44#include "llviewerregion.h" 48#include "llviewerregion.h"
45#include "llviewernetwork.h" // for gGridChoice 49#include "llviewernetwork.h" // for gGridChoice
@@ -56,12 +60,13 @@
56#include "llviewerparcelmgr.h" 60#include "llviewerparcelmgr.h"
57#include "llfirstuse.h" 61#include "llfirstuse.h"
58#include "llviewerwindow.h" 62#include "llviewerwindow.h"
63#include "llviewercamera.h"
59 64
60// for base64 decoding 65// for base64 decoding
61#include "apr-1/apr_base64.h" 66#include "apr_base64.h"
62 67
63// for SHA1 hash 68// for SHA1 hash
64#include "apr-1/apr_sha1.h" 69#include "apr_sha1.h"
65 70
66// If we are connecting to agni AND the user's last name is "Linden", join this channel instead of looking up the sim name. 71// If we are connecting to agni AND the user's last name is "Linden", join this channel instead of looking up the sim name.
67// If we are connecting to agni and the user's last name is NOT "Linden", disable voice. 72// If we are connecting to agni and the user's last name is NOT "Linden", disable voice.
@@ -218,6 +223,19 @@ void LLVivoxProtocolParser::reset()
218 ignoringTags = false; 223 ignoringTags = false;
219 accumulateText = false; 224 accumulateText = false;
220 textBuffer.clear(); 225 textBuffer.clear();
226
227 energy = 0.f;
228 ignoreDepth = 0;
229 isChannel = false;
230 isEvent = false;
231 isLocallyMuted = false;
232 isModeratorMuted = false;
233 isSpeaking = false;
234 participantType = 0;
235 returnCode = 0;
236 state = 0;
237 statusCode = 0;
238 volume = 0;
221} 239}
222 240
223//virtual 241//virtual
@@ -404,7 +422,7 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr)
404 422
405void LLVivoxProtocolParser::EndTag(const char *tag) 423void LLVivoxProtocolParser::EndTag(const char *tag)
406{ 424{
407 const char *string = textBuffer.c_str(); 425 const std::string& string = textBuffer;
408 bool clearbuffer = true; 426 bool clearbuffer = true;
409 427
410 responseDepth--; 428 responseDepth--;
@@ -428,9 +446,9 @@ void LLVivoxProtocolParser::EndTag(const char *tag)
428 446
429 // Closing a tag. Finalize the text we've accumulated and reset 447 // Closing a tag. Finalize the text we've accumulated and reset
430 if (strcmp("ReturnCode", tag) == 0) 448 if (strcmp("ReturnCode", tag) == 0)
431 returnCode = strtol(string, NULL, 10); 449 returnCode = strtol(string.c_str(), NULL, 10);
432 else if (strcmp("StatusCode", tag) == 0) 450 else if (strcmp("StatusCode", tag) == 0)
433 statusCode = strtol(string, NULL, 10); 451 statusCode = strtol(string.c_str(), NULL, 10);
434 else if (strcmp("ConnectorHandle", tag) == 0) 452 else if (strcmp("ConnectorHandle", tag) == 0)
435 connectorHandle = string; 453 connectorHandle = string;
436 else if (strcmp("AccountHandle", tag) == 0) 454 else if (strcmp("AccountHandle", tag) == 0)
@@ -445,11 +463,11 @@ void LLVivoxProtocolParser::EndTag(const char *tag)
445 else if (strcmp("StatusString", tag) == 0) 463 else if (strcmp("StatusString", tag) == 0)
446 statusString = string; 464 statusString = string;
447 else if (strcmp("State", tag) == 0) 465 else if (strcmp("State", tag) == 0)
448 state = strtol(string, NULL, 10); 466 state = strtol(string.c_str(), NULL, 10);
449 else if (strcmp("URI", tag) == 0) 467 else if (strcmp("URI", tag) == 0)
450 uriString = string; 468 uriString = string;
451 else if (strcmp("IsChannel", tag) == 0) 469 else if (strcmp("IsChannel", tag) == 0)
452 isChannel = strcmp(string, "true") == 0; 470 isChannel = string == "true" ? true : false;
453 else if (strcmp("Name", tag) == 0) 471 else if (strcmp("Name", tag) == 0)
454 nameString = string; 472 nameString = string;
455 else if (strcmp("AudioMedia", tag) == 0) 473 else if (strcmp("AudioMedia", tag) == 0)
@@ -463,19 +481,19 @@ void LLVivoxProtocolParser::EndTag(const char *tag)
463 else if (strcmp("AccountName", tag) == 0) 481 else if (strcmp("AccountName", tag) == 0)
464 nameString = string; 482 nameString = string;
465 else if (strcmp("ParticipantTyppe", tag) == 0) 483 else if (strcmp("ParticipantTyppe", tag) == 0)
466 participantType = strtol(string, NULL, 10); 484 participantType = strtol(string.c_str(), NULL, 10);
467 else if (strcmp("IsLocallyMuted", tag) == 0) 485 else if (strcmp("IsLocallyMuted", tag) == 0)
468 isLocallyMuted = strcmp(string, "true") == 0; 486 isLocallyMuted = string == "true" ? true : false;
469 else if (strcmp("IsModeratorMuted", tag) == 0) 487 else if (strcmp("IsModeratorMuted", tag) == 0)
470 isModeratorMuted = strcmp(string, "true") == 0; 488 isModeratorMuted = string == "true" ? true : false;
471 else if (strcmp("IsSpeaking", tag) == 0) 489 else if (strcmp("IsSpeaking", tag) == 0)
472 isSpeaking = strcmp(string, "true") == 0; 490 isSpeaking = string == "true" ? true : false;
473 else if (strcmp("Volume", tag) == 0) 491 else if (strcmp("Volume", tag) == 0)
474 volume = strtol(string, NULL, 10); 492 volume = strtol(string.c_str(), NULL, 10);
475 else if (strcmp("Energy", tag) == 0) 493 else if (strcmp("Energy", tag) == 0)
476 energy = (F32)strtod(string, NULL); 494 energy = (F32)strtod(string.c_str(), NULL);
477 else if (strcmp("MicEnergy", tag) == 0) 495 else if (strcmp("MicEnergy", tag) == 0)
478 energy = (F32)strtod(string, NULL); 496 energy = (F32)strtod(string.c_str(), NULL);
479 else if (strcmp("ChannelName", tag) == 0) 497 else if (strcmp("ChannelName", tag) == 0)
480 nameString = string; 498 nameString = string;
481 else if (strcmp("ChannelURI", tag) == 0) 499 else if (strcmp("ChannelURI", tag) == 0)
@@ -1079,9 +1097,9 @@ void LLVoiceClient::idle(void* user_data)
1079 self->stateMachine(); 1097 self->stateMachine();
1080} 1098}
1081 1099
1082const char *LLVoiceClient::state2string(LLVoiceClient::state inState) 1100std::string LLVoiceClient::state2string(LLVoiceClient::state inState)
1083{ 1101{
1084 const char *result = "UNKNOWN"; 1102 std::string result = "UNKNOWN";
1085 1103
1086 // Prevent copy-paste errors when updating this list... 1104 // Prevent copy-paste errors when updating this list...
1087#define CASE(x) case x: result = #x; break 1105#define CASE(x) case x: result = #x; break
@@ -1131,9 +1149,9 @@ const char *LLVoiceClient::state2string(LLVoiceClient::state inState)
1131 return result; 1149 return result;
1132} 1150}
1133 1151
1134const char *LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserver::EStatusType inStatus) 1152std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserver::EStatusType inStatus)
1135{ 1153{
1136 const char *result = "UNKNOWN"; 1154 std::string result = "UNKNOWN";
1137 1155
1138 // Prevent copy-paste errors when updating this list... 1156 // Prevent copy-paste errors when updating this list...
1139#define CASE(x) case x: result = #x; break 1157#define CASE(x) case x: result = #x; break
@@ -1174,7 +1192,11 @@ void LLVoiceClient::stateMachine()
1174 setVoiceEnabled(false); 1192 setVoiceEnabled(false);
1175 } 1193 }
1176 1194
1177 if(!mVoiceEnabled) 1195 if(mVoiceEnabled)
1196 {
1197 updatePosition();
1198 }
1199 else
1178 { 1200 {
1179 if(getState() != stateDisabled) 1201 if(getState() != stateDisabled)
1180 { 1202 {
@@ -1246,17 +1268,23 @@ void LLVoiceClient::stateMachine()
1246 if(true) 1268 if(true)
1247 { 1269 {
1248 // Launch the voice daemon 1270 // Launch the voice daemon
1249 std::string exe_path = gDirUtilp->getAppRODataDir(); 1271
1272 // *FIX:Mani - Using the executable dir instead
1273 // of mAppRODataDir, the working directory from which the app
1274 // is launched.
1275 //std::string exe_path = gDirUtilp->getAppRODataDir();
1276 std::string exe_path = gDirUtilp->getExecutableDir();
1250 exe_path += gDirUtilp->getDirDelimiter(); 1277 exe_path += gDirUtilp->getDirDelimiter();
1251#if LL_WINDOWS 1278#if LL_WINDOWS
1252 exe_path += "SLVoice.exe"; 1279 exe_path += "SLVoice.exe";
1280#elif LL_DARWIN
1281 exe_path += "../Resources/SLVoice";
1253#else 1282#else
1254 // This will be the same for mac and linux
1255 exe_path += "SLVoice"; 1283 exe_path += "SLVoice";
1256#endif 1284#endif
1257 // See if the vivox executable exists 1285 // See if the vivox executable exists
1258 llstat s; 1286 llstat s;
1259 if(!LLFile::stat(exe_path.c_str(), &s)) 1287 if(!LLFile::stat(exe_path, &s))
1260 { 1288 {
1261 // vivox executable exists. Build the command line and launch the daemon. 1289 // vivox executable exists. Build the command line and launch the daemon.
1262 std::string args = " -p tcp -h -c"; 1290 std::string args = " -p tcp -h -c";
@@ -1302,7 +1330,7 @@ void LLVoiceClient::stateMachine()
1302 // This should be the same for mac and linux 1330 // This should be the same for mac and linux
1303 { 1331 {
1304 std::vector<std::string> arglist; 1332 std::vector<std::string> arglist;
1305 arglist.push_back(exe_path.c_str()); 1333 arglist.push_back(exe_path);
1306 1334
1307 // Split the argument string into separate strings for each argument 1335 // Split the argument string into separate strings for each argument
1308 typedef boost::tokenizer<boost::char_separator<char> > tokenizer; 1336 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
@@ -1323,6 +1351,7 @@ void LLVoiceClient::stateMachine()
1323 1351
1324 fakeargv[i] = NULL; 1352 fakeargv[i] = NULL;
1325 1353
1354 fflush(NULL); // flush all buffers before the child inherits them
1326 pid_t id = vfork(); 1355 pid_t id = vfork();
1327 if(id == 0) 1356 if(id == 0)
1328 { 1357 {
@@ -1343,7 +1372,7 @@ void LLVoiceClient::stateMachine()
1343 } 1372 }
1344 else 1373 else
1345 { 1374 {
1346 LL_INFOS("Voice") << exe_path << "not found." << LL_ENDL 1375 LL_INFOS("Voice") << exe_path << "not found." << LL_ENDL;
1347 } 1376 }
1348 } 1377 }
1349 else 1378 else
@@ -1352,7 +1381,7 @@ void LLVoiceClient::stateMachine()
1352 // To do this, launch the gateway on a nearby host like this: 1381 // To do this, launch the gateway on a nearby host like this:
1353 // vivox-gw.exe -p tcp -i 0.0.0.0:44124 1382 // vivox-gw.exe -p tcp -i 0.0.0.0:44124
1354 // and put that host's IP address here. 1383 // and put that host's IP address here.
1355 mDaemonHost = LLHost(gSavedSettings.getString("VoiceHost").c_str(), gSavedSettings.getU32("VoicePort")); 1384 mDaemonHost = LLHost(gSavedSettings.getString("VoiceHost"), gSavedSettings.getU32("VoicePort"));
1356 } 1385 }
1357 1386
1358 mUpdateTimer.start(); 1387 mUpdateTimer.start();
@@ -2903,9 +2932,9 @@ void LLVoiceClient::sessionNewEvent(
2903 LLIMMgr::computeSessionID( 2932 LLIMMgr::computeSessionID(
2904 IM_SESSION_P2P_INVITE, 2933 IM_SESSION_P2P_INVITE,
2905 caller_id), 2934 caller_id),
2906 LLString::null, 2935 LLStringUtil::null,
2907 caller_id, 2936 caller_id,
2908 LLString::null, 2937 LLStringUtil::null,
2909 IM_SESSION_P2P_INVITE, 2938 IM_SESSION_P2P_INVITE,
2910 LLIMMgr::INVITATION_TYPE_VOICE, 2939 LLIMMgr::INVITATION_TYPE_VOICE,
2911 eventSessionHandle); 2940 eventSessionHandle);
@@ -3012,7 +3041,7 @@ void LLVoiceClient::muteListChanged()
3012///////////////////////////// 3041/////////////////////////////
3013// Managing list of participants 3042// Managing list of participants
3014LLVoiceClient::participantState::participantState(const std::string &uri) : 3043LLVoiceClient::participantState::participantState(const std::string &uri) :
3015 mURI(uri), mPTT(false), mIsSpeaking(false), mIsModeratorMuted(false), mPower(0.0), mServiceType(serviceTypeUnknown), 3044 mURI(uri), mPTT(false), mIsSpeaking(false), mIsModeratorMuted(false), mLastSpokeTimestamp(0.f), mPower(0.f), mVolume(0), mServiceType(serviceTypeUnknown),
3016 mOnMuteList(false), mUserVolume(100), mVolumeDirty(false), mAvatarIDValid(false) 3045 mOnMuteList(false), mUserVolume(100), mVolumeDirty(false), mAvatarIDValid(false)
3017{ 3046{
3018} 3047}
@@ -3402,18 +3431,15 @@ std::string LLVoiceClient::nameFromAvatar(LLVOAvatar *avatar)
3402std::string LLVoiceClient::nameFromID(const LLUUID &uuid) 3431std::string LLVoiceClient::nameFromID(const LLUUID &uuid)
3403{ 3432{
3404 std::string result; 3433 std::string result;
3405 U8 rawuuid[UUID_BYTES + 1];
3406 uuid.toCompressedString((char*)rawuuid);
3407
3408 // Prepending this apparently prevents conflicts with reserved names inside the vivox and diamondware code. 3434 // Prepending this apparently prevents conflicts with reserved names inside the vivox and diamondware code.
3409 result = "x"; 3435 result = "x";
3410 3436
3411 // Base64 encode and replace the pieces of base64 that are less compatible 3437 // Base64 encode and replace the pieces of base64 that are less compatible
3412 // with e-mail local-parts. 3438 // with e-mail local-parts.
3413 // See RFC-4648 "Base 64 Encoding with URL and Filename Safe Alphabet" 3439 // See RFC-4648 "Base 64 Encoding with URL and Filename Safe Alphabet"
3414 result += LLBase64::encode(rawuuid, UUID_BYTES); 3440 result += LLBase64::encode(uuid.mData, UUID_BYTES);
3415 LLString::replaceChar(result, '+', '-'); 3441 LLStringUtil::replaceChar(result, '+', '-');
3416 LLString::replaceChar(result, '/', '_'); 3442 LLStringUtil::replaceChar(result, '/', '_');
3417 3443
3418 // If you need to transform a GUID to this form on the Mac OS X command line, this will do so: 3444 // If you need to transform a GUID to this form on the Mac OS X command line, this will do so:
3419 // echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-') 3445 // echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-')
@@ -3435,16 +3461,14 @@ bool LLVoiceClient::IDFromName(const std::string name, LLUUID &uuid)
3435 3461
3436 // Reverse the transforms done by nameFromID 3462 // Reverse the transforms done by nameFromID
3437 std::string temp = name; 3463 std::string temp = name;
3438 LLString::replaceChar(temp, '-', '+'); 3464 LLStringUtil::replaceChar(temp, '-', '+');
3439 LLString::replaceChar(temp, '_', '/'); 3465 LLStringUtil::replaceChar(temp, '_', '/');
3440 3466
3441 U8 rawuuid[UUID_BYTES + 1]; 3467 U8 rawuuid[UUID_BYTES + 1];
3442 int len = apr_base64_decode_binary(rawuuid, temp.c_str() + 1); 3468 int len = apr_base64_decode_binary(rawuuid, temp.c_str() + 1);
3443 if(len == UUID_BYTES) 3469 if(len == UUID_BYTES)
3444 { 3470 {
3445 // The decode succeeded. Stuff the bits into the result's UUID 3471 // The decode succeeded. Stuff the bits into the result's UUID
3446 // MBW -- XXX -- there's no analogue of LLUUID::toCompressedString that allows you to set a UUID from binary data.
3447 // The data field is public, so we cheat thusly:
3448 memcpy(uuid.mData, rawuuid, UUID_BYTES); 3472 memcpy(uuid.mData, rawuuid, UUID_BYTES);
3449 result = true; 3473 result = true;
3450 } 3474 }
@@ -3466,7 +3490,7 @@ std::string LLVoiceClient::sipURIFromName(std::string &name)
3466 result += "@"; 3490 result += "@";
3467 result += mAccountServerName; 3491 result += mAccountServerName;
3468 3492
3469// LLString::toLower(result); 3493// LLStringUtil::toLower(result);
3470 3494
3471 return result; 3495 return result;
3472} 3496}
@@ -3497,6 +3521,45 @@ void LLVoiceClient::enforceTether(void)
3497 } 3521 }
3498} 3522}
3499 3523
3524void LLVoiceClient::updatePosition(void)
3525{
3526
3527 if(gVoiceClient)
3528 {
3529 LLVOAvatar *agent = gAgent.getAvatarObject();
3530 LLViewerRegion *region = gAgent.getRegion();
3531 if(region && agent)
3532 {
3533 LLMatrix3 rot;
3534 LLVector3d pos;
3535
3536 // MBW -- XXX -- Setting both camera and avatar velocity to 0 for now. May figure it out later...
3537
3538 // Send the current camera position to the voice code
3539 rot.setRows(LLViewerCamera::getInstance()->getAtAxis(), LLViewerCamera::getInstance()->getLeftAxis (), LLViewerCamera::getInstance()->getUpAxis());
3540 pos = gAgent.getRegion()->getPosGlobalFromRegion(LLViewerCamera::getInstance()->getOrigin());
3541
3542 gVoiceClient->setCameraPosition(
3543 pos, // position
3544 LLVector3::zero, // velocity
3545 rot); // rotation matrix
3546
3547 // Send the current avatar position to the voice code
3548 rot = agent->getRootJoint()->getWorldRotation().getMatrix3();
3549
3550 pos = agent->getPositionGlobal();
3551 // MBW -- XXX -- Can we get the head offset from outside the LLVOAvatar?
3552// pos += LLVector3d(mHeadOffset);
3553 pos += LLVector3d(0.f, 0.f, 1.f);
3554
3555 gVoiceClient->setAvatarPosition(
3556 pos, // position
3557 LLVector3::zero, // velocity
3558 rot); // rotation matrix
3559 }
3560 }
3561}
3562
3500void LLVoiceClient::setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot) 3563void LLVoiceClient::setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
3501{ 3564{
3502 mCameraRequestedPosition = position; 3565 mCameraRequestedPosition = position;
@@ -3831,9 +3894,9 @@ F32 LLVoiceClient::getCurrentPower(const LLUUID& id)
3831} 3894}
3832 3895
3833 3896
3834LLString LLVoiceClient::getDisplayName(const LLUUID& id) 3897std::string LLVoiceClient::getDisplayName(const LLUUID& id)
3835{ 3898{
3836 LLString result; 3899 std::string result;
3837 participantState *participant = findParticipantByID(id); 3900 participantState *participant = findParticipantByID(id);
3838 if(participant) 3901 if(participant)
3839 { 3902 {
@@ -4030,17 +4093,17 @@ void LLVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::EStatusTy
4030} 4093}
4031 4094
4032//static 4095//static
4033void LLVoiceClient::onAvatarNameLookup(const LLUUID& id, const char* first, const char* last, BOOL is_group, void* user_data) 4096// void LLVoiceClient::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* user_data)
4034{ 4097// {
4035 participantState* statep = gVoiceClient->findParticipantByID(id); 4098// participantState* statep = gVoiceClient->findParticipantByID(id);
4036 4099
4037 if (statep) 4100// if (statep)
4038 { 4101// {
4039 statep->mDisplayName = llformat("%s %s", first, last); 4102// statep->mDisplayName = first + " " + last;
4040 } 4103// }
4041 4104
4042 gVoiceClient->notifyObservers(); 4105// gVoiceClient->notifyObservers();
4043} 4106// }
4044 4107
4045class LLViewerParcelVoiceInfo : public LLHTTPNode 4108class LLViewerParcelVoiceInfo : public LLHTTPNode
4046{ 4109{
@@ -4052,6 +4115,9 @@ class LLViewerParcelVoiceInfo : public LLHTTPNode
4052 //the parcel you are in has changed something about its 4115 //the parcel you are in has changed something about its
4053 //voice information 4116 //voice information
4054 4117
4118 //this is a misnomer, as it can also be when you are not in
4119 //a parcel at all. Should really be something like
4120 //LLViewerVoiceInfoChanged.....
4055 if ( input.has("body") ) 4121 if ( input.has("body") )
4056 { 4122 {
4057 LLSD body = input["body"]; 4123 LLSD body = input["body"];
@@ -4061,6 +4127,11 @@ class LLViewerParcelVoiceInfo : public LLHTTPNode
4061 4127
4062 //body["voice_credentials"] has "channel_uri" (str), 4128 //body["voice_credentials"] has "channel_uri" (str),
4063 //body["voice_credentials"] has "channel_credentials" (str) 4129 //body["voice_credentials"] has "channel_credentials" (str)
4130
4131 //if we really wanted to be extra careful,
4132 //we'd check the supplied
4133 //local parcel id to make sure it's for the same parcel
4134 //we believe we're in
4064 if ( body.has("voice_credentials") ) 4135 if ( body.has("voice_credentials") )
4065 { 4136 {
4066 LLSD voice_credentials = body["voice_credentials"]; 4137 LLSD voice_credentials = body["voice_credentials"];