Merge branch 'master' of github.com:highfidelity/hifi into fix-audio-hmd-issue

This commit is contained in:
Dante Ruiz 2018-07-25 08:44:28 -07:00
commit a21a475784
13 changed files with 182 additions and 58 deletions

View file

@ -162,7 +162,19 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCrea
jvmArgs.version = JNI_VERSION_1_6; // choose your JNI version
jvmArgs.name = NULL; // you might want to give the java thread a name
jvmArgs.group = NULL; // you might want to assign the java thread to a ThreadGroup
jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&myNewEnv), &jvmArgs);
int attachedHere = 0; // know if detaching at the end is necessary
jint res = jvm->GetEnv((void**)&myNewEnv, JNI_VERSION_1_6); // checks if current env needs attaching or it is already attached
if (JNI_OK != res) {
qDebug() << "[JCRASH] GetEnv env not attached yet, attaching now..";
res = jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&myNewEnv), &jvmArgs);
if (JNI_OK != res) {
qDebug() << "[JCRASH] Failed to AttachCurrentThread, ErrorCode = " << res;
return;
} else {
attachedHere = 1;
}
}
QAndroidJniObject string = QAndroidJniObject::fromString(a);
jboolean jBackToScene = (jboolean) backToScene;
@ -175,7 +187,9 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCrea
myNewEnv->CallObjectMethod(hashmap, mapClassPut, QAndroidJniObject::fromString("url").object<jstring>(), jArg.object<jstring>());
}
__interfaceActivity.callMethod<void>("openAndroidActivity", "(Ljava/lang/String;ZLjava/util/HashMap;)V", string.object<jstring>(), jBackToScene, hashmap);
jvm->DetachCurrentThread();
if (attachedHere) {
jvm->DetachCurrentThread();
}
});
QObject::connect(&AndroidHelper::instance(), &AndroidHelper::hapticFeedbackRequested, [](int duration) {

View file

@ -299,7 +299,7 @@ Item {
anchors.fill: stackView
id: controllerPrefereneces
objectName: "TabletControllerPreferences"
showCategories: ["VR Movement", "Game Controller", "Sixense Controllers", "Perception Neuron", "Leap Motion"]
showCategories: [( (HMD.active) ? "VR Movement" : "Movement"), "Game Controller", "Sixense Controllers", "Perception Neuron", "Leap Motion"]
categoryProperties: {
"VR Movement" : {
"User real-world height (meters)" : { "anchors.right" : "undefined" },

View file

@ -3650,6 +3650,10 @@ bool Application::event(QEvent* event) {
bool Application::eventFilter(QObject* object, QEvent* event) {
if (_aboutToQuit) {
return true;
}
if (event->type() == QEvent::Leave) {
getApplicationCompositor().handleLeaveEvent();
}
@ -4839,6 +4843,13 @@ void Application::loadSettings() {
}
isFirstPerson = (qApp->isHMDMode());
// Flying should be disabled by default in HMD mode on first run, and it
// should be enabled by default in desktop mode.
auto myAvatar = getMyAvatar();
myAvatar->setFlyingEnabled(!isFirstPerson);
} else {
// if this is not the first run, the camera will be initialized differently depending on user settings

View file

@ -144,9 +144,19 @@ void AvatarBookmarks::removeBookmark(const QString& bookmarkName) {
emit bookmarkDeleted(bookmarkName);
}
bool isWearableEntity(const EntityItemPointer& entity) {
return entity->isVisible() && entity->getParentJointIndex() != INVALID_JOINT_INDEX &&
(entity->getParentID() == DependencyManager::get<NodeList>()->getSessionUUID() || entity->getParentID() == DependencyManager::get<AvatarManager>()->getMyAvatar()->getSelfID());
}
void AvatarBookmarks::updateAvatarEntities(const QVariantList &avatarEntities) {
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
myAvatar->removeAvatarEntities();
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
myAvatar->removeAvatarEntities([&](const QUuid& entityID) {
auto entity = entityTree->findEntityByID(entityID);
return entity && isWearableEntity(entity);
});
addAvatarEntities(avatarEntities);
}
@ -163,7 +173,12 @@ void AvatarBookmarks::loadBookmark(const QString& bookmarkName) {
QVariantMap bookmark = bookmarkEntry.value().toMap();
if (!bookmark.empty()) {
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
myAvatar->removeAvatarEntities();
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
myAvatar->removeAvatarEntities([&](const QUuid& entityID) {
auto entity = entityTree->findEntityByID(entityID);
return entity && isWearableEntity(entity);
});
const QString& avatarUrl = bookmark.value(ENTRY_AVATAR_URL, "").toString();
myAvatar->useFullAvatarURL(avatarUrl);
qCDebug(interfaceapp) << "Avatar On " << avatarUrl;
@ -233,6 +248,27 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() {
bookmark.insert(ENTRY_AVATAR_URL, avatarUrl);
bookmark.insert(ENTRY_AVATAR_SCALE, avatarScale);
bookmark.insert(ENTRY_AVATAR_ATTACHMENTS, myAvatar->getAttachmentsVariant());
bookmark.insert(ENTRY_AVATAR_ENTITIES, myAvatar->getAvatarEntitiesVariant());
QScriptEngine scriptEngine;
QVariantList wearableEntities;
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
auto avatarEntities = myAvatar->getAvatarEntityData();
for (auto entityID : avatarEntities.keys()) {
auto entity = entityTree->findEntityByID(entityID);
if (!entity || !isWearableEntity(entity)) {
continue;
}
QVariantMap avatarEntityData;
EncodeBitstreamParams params;
auto desiredProperties = entity->getEntityProperties(params);
desiredProperties += PROP_LOCAL_POSITION;
desiredProperties += PROP_LOCAL_ROTATION;
EntityItemProperties entityProperties = entity->getProperties(desiredProperties);
QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(&scriptEngine, entityProperties);
avatarEntityData["properties"] = scriptProperties.toVariant();
wearableEntities.append(QVariant(avatarEntityData));
}
bookmark.insert(ENTRY_AVATAR_ENTITIES, wearableEntities);
return bookmark;
}

View file

@ -1281,7 +1281,8 @@ void MyAvatar::loadData() {
settings.remove("avatarEntityData");
}
setAvatarEntityDataChanged(true);
setFlyingEnabled(settings.value("enabledFlying").toBool());
Setting::Handle<bool> firstRunVal { Settings::firstRun, true };
setFlyingEnabled(firstRunVal.get() ? getFlyingEnabled() : settings.value("enabledFlying").toBool());
setDisplayName(settings.value("displayName").toString());
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
@ -1607,14 +1608,16 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
emit skeletonModelURLChanged();
}
void MyAvatar::removeAvatarEntities() {
void MyAvatar::removeAvatarEntities(const std::function<bool(const QUuid& entityID)>& condition) {
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
if (entityTree) {
entityTree->withWriteLock([&] {
AvatarEntityMap avatarEntities = getAvatarEntityData();
for (auto entityID : avatarEntities.keys()) {
entityTree->deleteEntity(entityID, true, true);
if (!condition || condition(entityID)) {
entityTree->deleteEntity(entityID, true, true);
}
}
});
}

View file

@ -33,6 +33,7 @@
#include "MyCharacterController.h"
#include "RingBufferHistory.h"
#include <ThreadSafeValueCache.h>
#include <EntityItem.h>
class AvatarActionHold;
class ModelItemID;
@ -926,7 +927,7 @@ public:
* @returns {object[]}
*/
Q_INVOKABLE QVariantList getAvatarEntitiesVariant();
void removeAvatarEntities();
void removeAvatarEntities(const std::function<bool(const QUuid& entityID)>& condition = {});
/**jsdoc
* @function MyAvatar.isFlying

View file

@ -266,20 +266,15 @@ void setupPreferences() {
preferences->addPreference(new SliderPreference(FACE_TRACKING, "Eye Deflection", getter, setter));
}
static const QString MOVEMENT{ "VR Movement" };
static const QString MOVEMENT{ "Movement" };
{
static const QString movementsControlChannel = QStringLiteral("Hifi-Advanced-Movement-Disabler");
auto getter = [=]()->bool { return myAvatar->useAdvancedMovementControls(); };
auto setter = [=](bool value) { myAvatar->setUseAdvancedMovementControls(value); };
preferences->addPreference(new CheckPreference(MOVEMENT,
QStringLiteral("Advanced movement for hand controllers"),
getter, setter));
}
{
auto getter = [=]()->bool { return myAvatar->getFlyingEnabled(); };
auto setter = [=](bool value) { myAvatar->setFlyingEnabled(value); };
preferences->addPreference(new CheckPreference(MOVEMENT, "Flying & jumping", getter, setter));
QStringLiteral("Advanced movement for hand controllers"),
getter, setter));
}
{
auto getter = [=]()->int { return myAvatar->getSnapTurn() ? 0 : 1; };
@ -307,6 +302,47 @@ void setupPreferences() {
preferences->addPreference(preference);
}
static const QString VR_MOVEMENT{ "VR Movement" };
{
static const QString movementsControlChannel = QStringLiteral("Hifi-Advanced-Movement-Disabler");
auto getter = [=]()->bool { return myAvatar->useAdvancedMovementControls(); };
auto setter = [=](bool value) { myAvatar->setUseAdvancedMovementControls(value); };
preferences->addPreference(new CheckPreference(VR_MOVEMENT,
QStringLiteral("Advanced movement for hand controllers"),
getter, setter));
}
{
auto getter = [=]()->bool { return myAvatar->getFlyingEnabled(); };
auto setter = [=](bool value) { myAvatar->setFlyingEnabled(value); };
preferences->addPreference(new CheckPreference(VR_MOVEMENT, "Flying & jumping", getter, setter));
}
{
auto getter = [=]()->int { return myAvatar->getSnapTurn() ? 0 : 1; };
auto setter = [=](int value) { myAvatar->setSnapTurn(value == 0); };
auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Snap turn / Smooth turn", getter, setter);
QStringList items;
items << "Snap turn" << "Smooth turn";
preference->setItems(items);
preferences->addPreference(preference);
}
{
auto getter = [=]()->float { return myAvatar->getUserHeight(); };
auto setter = [=](float value) { myAvatar->setUserHeight(value); };
auto preference = new SpinnerPreference(VR_MOVEMENT, "User real-world height (meters)", getter, setter);
preference->setMin(1.0f);
preference->setMax(2.2f);
preference->setDecimals(3);
preference->setStep(0.001f);
preferences->addPreference(preference);
}
{
auto preference = new ButtonPreference(VR_MOVEMENT, "RESET SENSORS", [] {
qApp->resetSensors();
});
preferences->addPreference(preference);
}
static const QString AVATAR_CAMERA{ "Mouse Sensitivity" };
{
auto getter = [=]()->float { return myAvatar->getPitchSpeed(); };

View file

@ -1,5 +1,8 @@
set(TARGET_NAME audio-client)
setup_hifi_library(Network Multimedia)
if (ANDROID)
set(PLATFORM_QT_COMPONENTS AndroidExtras)
endif ()
setup_hifi_library(Network Multimedia ${PLATFORM_QT_COMPONENTS})
link_hifi_libraries(audio plugins)
include_hifi_library_headers(shared)
include_hifi_library_headers(networking)

View file

@ -52,6 +52,10 @@
#include "AudioLogging.h"
#include "AudioHelpers.h"
#if defined(Q_OS_ANDROID)
#include <QtAndroidExtras/QAndroidJniObject>
#endif
const int AudioClient::MIN_BUFFER_FRAMES = 1;
const int AudioClient::MAX_BUFFER_FRAMES = 20;
@ -60,7 +64,7 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100;
#if defined(Q_OS_ANDROID)
static const int CHECK_INPUT_READS_MSECS = 2000;
static const int MIN_READS_TO_CONSIDER_INPUT_ALIVE = 100;
static const int MIN_READS_TO_CONSIDER_INPUT_ALIVE = 10;
#endif
static const auto DEFAULT_POSITION_GETTER = []{ return Vectors::ZERO; };
@ -235,7 +239,7 @@ AudioClient::AudioClient() :
// start a thread to detect any device changes
_checkDevicesTimer = new QTimer(this);
connect(_checkDevicesTimer, &QTimer::timeout, [this] {
connect(_checkDevicesTimer, &QTimer::timeout, this, [this] {
QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkDevices(); });
});
const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000;
@ -243,7 +247,7 @@ AudioClient::AudioClient() :
// start a thread to detect peak value changes
_checkPeakValuesTimer = new QTimer(this);
connect(_checkPeakValuesTimer, &QTimer::timeout, [this] {
connect(_checkPeakValuesTimer, &QTimer::timeout, this, [this] {
QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkPeakValues(); });
});
const unsigned long PEAK_VALUES_CHECK_INTERVAL_MSECS = 50;
@ -482,6 +486,15 @@ bool nativeFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
audioFormat.setSampleType(QAudioFormat::SignedInt);
audioFormat.setByteOrder(QAudioFormat::LittleEndian);
#if defined(Q_OS_ANDROID)
// Using the HW sample rate (AUDIO_INPUT_FLAG_FAST) in some samsung phones causes a low volume at input stream
// Changing the sample rate forces a resampling that (in samsung) amplifies +18 dB
QAndroidJniObject brand = QAndroidJniObject::getStaticObjectField<jstring>("android/os/Build", "BRAND");
if (audioDevice == QAudioDeviceInfo::defaultInputDevice() && brand.toString().contains("samsung", Qt::CaseInsensitive)) {
audioFormat.setSampleRate(24000);
}
#endif
if (!audioDevice.isFormatSupported(audioFormat)) {
qCWarning(audioclient) << "The native format is" << audioFormat << "but isFormatSupported() failed.";
return false;
@ -635,9 +648,7 @@ void AudioClient::start() {
qCDebug(audioclient) << "The closest format available is" << outputDeviceInfo.nearestFormat(_desiredOutputFormat);
}
#if defined(Q_OS_ANDROID)
connect(&_checkInputTimer, &QTimer::timeout, [this] {
checkInputTimeout();
});
connect(&_checkInputTimer, &QTimer::timeout, this, &AudioClient::checkInputTimeout);
_checkInputTimer.start(CHECK_INPUT_READS_MSECS);
#endif
}
@ -651,6 +662,7 @@ void AudioClient::stop() {
switchOutputToAudioDevice(QAudioDeviceInfo(), true);
#if defined(Q_OS_ANDROID)
_checkInputTimer.stop();
disconnect(&_checkInputTimer, &QTimer::timeout, 0, 0);
#endif
}
@ -1558,9 +1570,7 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInf
#if defined(Q_OS_ANDROID)
if (_audioInput) {
_shouldRestartInputSetup = true;
connect(_audioInput, &QAudioInput::stateChanged, [this](QAudio::State state) {
audioInputStateChanged(state);
});
connect(_audioInput, &QAudioInput::stateChanged, this, &AudioClient::audioInputStateChanged);
}
#endif
_inputDevice = _audioInput->start();
@ -1764,7 +1774,7 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
_outputScratchBuffer = new int16_t[_outputPeriod];
// size local output mix buffer based on resampled network frame size
int networkPeriod = _localToOutputResampler->getMaxOutput(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO);
int networkPeriod = _localToOutputResampler ? _localToOutputResampler->getMaxOutput(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO) : AudioConstants::NETWORK_FRAME_SAMPLES_STEREO;
_localOutputMixBuffer = new float[networkPeriod];
// local period should be at least twice the output period,

View file

@ -229,7 +229,7 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc
if (bytesWritten < 0) {
// when saturating a link this isn't an uncommon message - suppress it so it doesn't bomb the debug
HIFI_FCDEBUG(networking(), "Socket::writeDatagram" << _udpSocket.error() << "-" << qPrintable(_udpSocket.errorString()) );
HIFI_FCDEBUG(networking(), "Socket::writeDatagram" << _udpSocket.error());
}
return bytesWritten;
@ -513,7 +513,7 @@ std::vector<HifiSockAddr> Socket::getConnectionSockAddrs() {
}
void Socket::handleSocketError(QAbstractSocket::SocketError socketError) {
HIFI_FCDEBUG(networking(), "udt::Socket error - " << socketError << _udpSocket.errorString());
HIFI_FCDEBUG(networking(), "udt::Socket error - " << socketError);
}
void Socket::handleStateChanged(QAbstractSocket::SocketState socketState) {

View file

@ -29,13 +29,25 @@ function executeLater(callback) {
Script.setTimeout(callback, 300);
}
function getMyAvatarWearables() {
var wearablesArray = MyAvatar.getAvatarEntitiesVariant();
var INVALID_JOINT_INDEX = -1
function isWearable(avatarEntity) {
return avatarEntity.properties.visible === true && avatarEntity.properties.parentJointIndex !== INVALID_JOINT_INDEX &&
(avatarEntity.properties.parentID === MyAvatar.sessionUUID || avatarEntity.properties.parentID === MyAvatar.SELF_ID);
}
for(var i = 0; i < wearablesArray.length; ++i) {
var wearable = wearablesArray[i];
var localRotation = wearable.properties.localRotation;
wearable.properties.localRotationAngles = Quat.safeEulerAngles(localRotation)
function getMyAvatarWearables() {
var entitiesArray = MyAvatar.getAvatarEntitiesVariant();
var wearablesArray = [];
for (var i = 0; i < entitiesArray.length; ++i) {
var entity = entitiesArray[i];
if (!isWearable(entity)) {
continue;
}
var localRotation = entity.properties.localRotation;
entity.properties.localRotationAngles = Quat.safeEulerAngles(localRotation)
wearablesArray.push(entity);
}
return wearablesArray;
@ -443,10 +455,6 @@ startup();
var isWired = false;
function off() {
if (isWired) { // It is not ok to disconnect these twice, hence guard.
isWired = false;
}
if(adjustWearables.opened) {
adjustWearables.setOpened(false);
ensureWearableSelected(null);
@ -456,16 +464,20 @@ function off() {
Messages.unsubscribe('Hifi-Object-Manipulation');
}
AvatarBookmarks.bookmarkLoaded.disconnect(onBookmarkLoaded);
AvatarBookmarks.bookmarkDeleted.disconnect(onBookmarkDeleted);
AvatarBookmarks.bookmarkAdded.disconnect(onBookmarkAdded);
if (isWired) { // It is not ok to disconnect these twice, hence guard.
isWired = false;
MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged);
MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged);
MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged);
MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl);
MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged);
MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged);
AvatarBookmarks.bookmarkLoaded.disconnect(onBookmarkLoaded);
AvatarBookmarks.bookmarkDeleted.disconnect(onBookmarkDeleted);
AvatarBookmarks.bookmarkAdded.disconnect(onBookmarkAdded);
MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged);
MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged);
MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged);
MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl);
MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged);
MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged);
}
}
function on() {

View file

@ -263,7 +263,7 @@ SelectionManager = (function() {
that.worldDimensions = properties.boundingBox.dimensions;
that.worldPosition = properties.boundingBox.center;
that.worldRotation = properties.boundingBox.rotation;
that.worldRotation = Quat.IDENTITY;
that.entityType = properties.type;
@ -271,10 +271,6 @@ SelectionManager = (function() {
SelectionDisplay.setSpaceMode(SPACE_LOCAL);
}
} else {
that.localRotation = null;
that.localDimensions = null;
that.localPosition = null;
properties = Entities.getEntityProperties(that.selections[0]);
that.entityType = properties.type;
@ -293,6 +289,7 @@ SelectionManager = (function() {
tfl.z = Math.max(bb.tfl.z, tfl.z);
}
that.localRotation = null;
that.localDimensions = null;
that.localPosition = null;
that.worldDimensions = {
@ -300,6 +297,7 @@ SelectionManager = (function() {
y: tfl.y - brn.y,
z: tfl.z - brn.z
};
that.worldRotation = Quat.IDENTITY;
that.worldPosition = {
x: brn.x + (that.worldDimensions.x / 2),
y: brn.y + (that.worldDimensions.y / 2),

View file

@ -405,7 +405,7 @@ LogWindow.prototype = {
}
};
function goHomeClicked() {
function visitSandboxClicked() {
if (interfacePath) {
startInterface('hifi://localhost');
} else {
@ -439,8 +439,8 @@ var labels = {
}
},
goHome: {
label: 'Go Home',
click: goHomeClicked,
label: 'Visit Sandbox',
click: visitSandboxClicked,
enabled: false
},
quit: {