Version 1.18.0 alexa-client-sdk
Changes in this update: **Enhancements** * Added support for [Bluetooth Interface 2.0](https://developer.amazon.com/docs/alexa/alexa-voice-service/bluetooth.html). This interface adds support for multiple simultaneous connections to Bluetooth peripherals. * Added support for [Audio Focus Manager Library (AFML) Multi Activity](https://developer.amazon.com/docs/alexa/avs-device-sdk/sdk-interaction-model.html). This interface enhances the behavior of a device so it can handle more than one Activity per Channel. * Added the `obfuscatePrivateData` logging method to help remove certain data from logs. * Updated `MediaPlayerObserverInterface` to include metadata about playback states. * Added SDK extension point. You can integrate CMake projects into the SDK without cloning those projects into a subdirectory. **Bug fixes** * Fixed Mac/OSX issue that caused an unresponsive Sample App when not connected to the internet. * Fixed issue that prevented sample app from exiting various states. * Fixed `UIManager` issue that caused an error in the logs when the device with built without the wake word enabled. * Fixed volume issue that caused timers to ascend in volume when setting up ascending alarms. * Fixed alert volume issue that caused any changes to the alert volume to notify observers. * Fixed EQ issue where changes to the EQ band levels didn't notify observers. * Fixed Bluetooth bug that caused short notification sounds from a connected phone to stop audio playback on the device. **Known Issues** * Build errors can occur on the Raspberry Pi due to incorrect linking of the atomic library. A suggested workaround is to add the following `set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -latomic")` to the top most CMake file. * The WebVTT dependency required for `captions` isn't supported for Windows/Android. * Exiting from the setting option takes you back to the Options Menu directly. It doesn't provide a message to indicate that you're back in the main menu. * Failing Unit Tests and AIP Unit tests are disabled on Windows * `AudioInputProcessor` unit tests don't build on Windows when with the `-DCMAKE_BUILD_TYPE=DEBUG` cmake parameter. * Music playback history isn't displayed in the Alexa app for certain account and device types. * When using Gnu Compiler Collection 8+ (GCC 8+), `-Wclass-memaccess` triggers warnings. You can ignore these, they don't cause the build to fail. * Android error `libDefaultClient.so not found` might occur. Resolve this by upgrading to ADB version 1.0.40. * If a device loses a network connection, the lost connection status isn't returned though local TTS. * ACL encounters issues if it receives audio attachments but doesn't consume them. * Media streamed through Bluetooth might abruptly stop. To restart playback, resume the media in the source application or toggle next/previous. * If a connected Bluetooth device is inactive, the Alexa app might indicates that audio is playing. * The Bluetooth agent assumes that the Bluetooth adapter is always connected to a power source. Disconnecting from a power source during operation isn't yet supported. * When using some products, interrupted Bluetooth playback might not resume if other content is locally streamed. * `make integration` isn't available for Android. To run Android integration tests, manually upload the test binary and input file and run ADB. * Alexa might truncate the beginning of speech when responding to text-to-speech (TTS) user events. This only impacts Raspberry Pi devices running Android Things with HDMI output audio. * A reminder TTS message doesn't play if the sample app restarts and loses a network connection. Instead, the default alarm tone plays twice. * `ServerDisconnectIntegratonTest` tests are disabled until they are updated to reflect new service behavior. * The `DirectiveSequencerTest.test_handleBlockingThenImmediatelyThenNonBockingOnSameDialogId` test fails intermittently.
This commit is contained in:
parent
f2353770ac
commit
b1ef879eb0
ACL
ADSL
include/ADSL
src
test
AFML
include/AFML
src
test
AVSCommon
AVS
include/AVSCommon/AVS
AVSDirective.hAVSDiscoveryEndpointAttributes.hAVSMessageEndpoint.hAlexaAssetId.hAlexaResponseType.hAlexaUnitOfMeasure.h
Attachment
AudioInputStream.hCapabilityAgent.hCapabilityResources.hContentType.hDialogUXStateAggregator.hFocusState.hIndicatorState.hInitialization
MixingBehavior.hPlayRequestor.hStateRefreshPolicy.hsrc
AVSContext.cppAVSDirective.cppAlexaClientSDKInit.cpp
Attachment
CapabilityAgent.cppDialogUXStateAggregator.cppMessageRequest.cpptest
SDKInterfaces/include/AVSCommon/SDKInterfaces
AVSGatewayManagerInterface.hAVSGatewayObserverInterface.h
Audio
AudioInputProcessorObserverInterface.hBluetooth
BluetoothDeviceConnectionRuleInterface.hBluetoothDeviceInterface.hBluetoothHostControllerInterface.h
CallManagerInterface.hCallStateObserverInterface.hCapabilitiesDelegateInterface.hChannelObserverInterface.hContextManagerInterface.hExternalMediaAdapterInterface.hExternalMediaPlayerObserverInterface.hFocusManagerInterface.hServices
ModeController
PowerResourceManagerInterface.hRangeController
SpeakerInterface.h
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2016-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2016-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2016-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2016-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -27,16 +27,18 @@
|
|||
#include <unordered_set>
|
||||
|
||||
#include <AVSCommon/AVS/Attachment/AttachmentManager.h>
|
||||
#include <AVSCommon/Utils/HTTP2/HTTP2ConnectionInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/AuthDelegateInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/PostConnectSendMessageInterface.h>
|
||||
#include <AVSCommon/Utils/HTTP2/HTTP2ConnectionInterface.h>
|
||||
#include <AVSCommon/Utils/HTTP2/HTTP2ConnectionObserverInterface.h>
|
||||
#include <AVSCommon/Utils/Metrics/MetricRecorderInterface.h>
|
||||
|
||||
#include "ACL/Transport/MessageConsumerInterface.h"
|
||||
#include "ACL/Transport/PingHandler.h"
|
||||
#include "ACL/Transport/PostConnectFactoryInterface.h"
|
||||
#include "ACL/Transport/PostConnectObserverInterface.h"
|
||||
#include "ACL/Transport/TransportInterface.h"
|
||||
#include "ACL/Transport/TransportObserverInterface.h"
|
||||
#include "ACL/Transport/SynchronizedMessageRequestQueue.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace acl {
|
||||
|
@ -50,6 +52,7 @@ class HTTP2Transport
|
|||
, public PostConnectObserverInterface
|
||||
, public avsCommon::sdkInterfaces::PostConnectSendMessageInterface
|
||||
, public avsCommon::sdkInterfaces::AuthObserverInterface
|
||||
, public avsCommon::utils::http2::HTTP2ConnectionObserverInterface
|
||||
, public ExchangeHandlerContextInterface {
|
||||
public:
|
||||
/*
|
||||
|
@ -75,7 +78,9 @@ public:
|
|||
* @param attachmentManager The attachment manager that manages the attachments.
|
||||
* @param transportObserver The observer of the new instance of TransportInterface.
|
||||
* @param postConnectFactory The object used to create @c PostConnectInterface instances.
|
||||
* @param sharedRequestQueue Request queue shared by all instances of HTTPTransportInterface.
|
||||
* @param configuration An optional configuration to specify HTTP2/2 connection settings.
|
||||
* @param metricRecorder The metric recorder.
|
||||
* @return A shared pointer to a HTTP2Transport object.
|
||||
*/
|
||||
static std::shared_ptr<HTTP2Transport> create(
|
||||
|
@ -86,7 +91,9 @@ public:
|
|||
std::shared_ptr<avsCommon::avs::attachment::AttachmentManager> attachmentManager,
|
||||
std::shared_ptr<TransportObserverInterface> transportObserver,
|
||||
std::shared_ptr<PostConnectFactoryInterface> postConnectFactory,
|
||||
Configuration configuration = Configuration());
|
||||
std::shared_ptr<SynchronizedMessageRequestQueue> sharedRequestQueue,
|
||||
Configuration configuration = Configuration(),
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder = nullptr);
|
||||
|
||||
/**
|
||||
* Method to add a TransportObserverInterface instance.
|
||||
|
@ -114,7 +121,7 @@ public:
|
|||
bool connect() override;
|
||||
void disconnect() override;
|
||||
bool isConnected() override;
|
||||
void send(std::shared_ptr<avsCommon::avs::MessageRequest> request) override;
|
||||
void onRequestEnqueued() override;
|
||||
/// @}
|
||||
|
||||
/// @name PostConnectSendMessageInterface methods.
|
||||
|
@ -157,6 +164,10 @@ public:
|
|||
std::string getAVSGateway() override;
|
||||
/// @}
|
||||
|
||||
/// @name HTTP2ConnectionObserverInterface methods.
|
||||
void onGoawayReceived() override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Enum to track the (internal) state of the HTTP2Transport
|
||||
|
@ -196,7 +207,9 @@ private:
|
|||
* @param attachmentManager The attachment manager that manages the attachments.
|
||||
* @param transportObserver The observer of the new instance of TransportInterface.
|
||||
* @param postConnect The object used to create PostConnectInterface instances.
|
||||
* @param sharedRequestQueue Request queue shared by all instances of HTTPTransportInterface.
|
||||
* @param configuration The HTTP2/2 connection settings.
|
||||
* @param metricRecorder The metric recorder.
|
||||
*/
|
||||
HTTP2Transport(
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::AuthDelegateInterface> authDelegate,
|
||||
|
@ -206,7 +219,9 @@ private:
|
|||
std::shared_ptr<avsCommon::avs::attachment::AttachmentManager> attachmentManager,
|
||||
std::shared_ptr<TransportObserverInterface> transportObserver,
|
||||
std::shared_ptr<PostConnectFactoryInterface> postConnectFactory,
|
||||
Configuration configuration);
|
||||
std::shared_ptr<SynchronizedMessageRequestQueue> sharedRequestQueue,
|
||||
Configuration configuration,
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder);
|
||||
|
||||
/**
|
||||
* Main loop for servicing the various states.
|
||||
|
@ -277,12 +292,17 @@ private:
|
|||
State handleShutdown();
|
||||
|
||||
/**
|
||||
* Enqueue a MessageRequest for sending.
|
||||
* Monitor the shared message queue while waiting for a state change. If messages have been sitting in the
|
||||
* queue for too long (e.g. during prolonged internet connectivity outtage), complete them as TIMEDOUT.
|
||||
*
|
||||
* @param request The MessageRequest to enqueue.
|
||||
* @param beforeConnected Whether or not to only allow enqueuing of messages before connected.
|
||||
* @param whileState The @c State to keep waiting in.
|
||||
* @param wakeTime The max time point to wait for.
|
||||
* @return The new state.
|
||||
*/
|
||||
void enqueueRequest(std::shared_ptr<avsCommon::avs::MessageRequest> request, bool beforeConnected);
|
||||
State monitorSharedQueueWhileWaiting(
|
||||
State whileState,
|
||||
std::chrono::time_point<std::chrono::steady_clock> maxWakeTime =
|
||||
std::chrono::time_point<std::chrono::steady_clock>::max());
|
||||
|
||||
/**
|
||||
* Handle sending @c MessageRequests and pings while in @c State::POST_CONNECTING or @c State::CONNECTED.
|
||||
|
@ -290,7 +310,7 @@ private:
|
|||
* @param whileState Continue sending @c MessageRequests and pings while in this state.
|
||||
* @return The current value of @c m_state.
|
||||
*/
|
||||
State sendMessagesAndPings(State whileState);
|
||||
State sendMessagesAndPings(State whileState, MessageRequestQueueInterface& requestQueue);
|
||||
|
||||
/**
|
||||
* Set the state to a new state.
|
||||
|
@ -342,6 +362,9 @@ private:
|
|||
*/
|
||||
State getState();
|
||||
|
||||
/// The metric recorder.
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> m_metricRecorder;
|
||||
|
||||
/// Mutex for accessing @c m_state and @c m_messageQueue
|
||||
std::mutex m_mutex;
|
||||
|
||||
|
@ -369,6 +392,9 @@ private:
|
|||
/// Factory for creating @c PostConnectInterface instances.
|
||||
std::shared_ptr<PostConnectFactoryInterface> m_postConnectFactory;
|
||||
|
||||
/// Queue of @c MessageRequest instances to send that are shared between instances of @c HTTP2Transport.
|
||||
std::shared_ptr<SynchronizedMessageRequestQueue> m_sharedRequestQueue;
|
||||
|
||||
/// Mutex to protect access to the m_observers variable.
|
||||
std::mutex m_observerMutex;
|
||||
|
||||
|
@ -381,15 +407,12 @@ private:
|
|||
/// PostConnect object is used to perform activities required once a connection is established.
|
||||
std::shared_ptr<PostConnectInterface> m_postConnect;
|
||||
|
||||
/// Queue of @c MessageRequest instances to send. Serialized by @c m_mutex.
|
||||
std::deque<std::shared_ptr<avsCommon::avs::MessageRequest>> m_requestQueue;
|
||||
/// Queue of @c MessageRequest instances to send during the POST_CONNECTING state. Serialized by @c m_mutex.
|
||||
MessageRequestQueue m_requestQueue;
|
||||
|
||||
/// Number of times connecting has been retried.
|
||||
int m_connectRetryCount;
|
||||
|
||||
/// Is a message handler awaiting a response?
|
||||
bool m_isMessageHandlerAwaitingResponse;
|
||||
|
||||
/// The number of message handlers that are not finished with their request.
|
||||
int m_countOfUnfinishedMessageHandlers;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -22,6 +22,7 @@
|
|||
#include <AVSCommon/AVS/Attachment/AttachmentManager.h>
|
||||
#include <AVSCommon/SDKInterfaces/AuthDelegateInterface.h>
|
||||
#include <AVSCommon/Utils/HTTP2/HTTP2ConnectionFactoryInterface.h>
|
||||
#include <AVSCommon/Utils/Metrics/MetricRecorderInterface.h>
|
||||
|
||||
#include "ACL/Transport/MessageConsumerInterface.h"
|
||||
#include "ACL/Transport/PostConnectFactoryInterface.h"
|
||||
|
@ -41,10 +42,12 @@ public:
|
|||
*
|
||||
* @param connectionFactory Object used to create instances of HTTP2ConnectionInterface.
|
||||
* @param postConnectFactory Object used to create instances of the PostConnectInterface.
|
||||
* @param metricRecorder The metric recorder.
|
||||
*/
|
||||
HTTP2TransportFactory(
|
||||
std::shared_ptr<avsCommon::utils::http2::HTTP2ConnectionFactoryInterface> connectionFactory,
|
||||
std::shared_ptr<PostConnectFactoryInterface> postConnectFactory);
|
||||
std::shared_ptr<PostConnectFactoryInterface> postConnectFactory,
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder = nullptr);
|
||||
|
||||
/// @name TransportFactoryInterface methods.
|
||||
/// @{
|
||||
|
@ -53,7 +56,8 @@ public:
|
|||
std::shared_ptr<avsCommon::avs::attachment::AttachmentManager> attachmentManager,
|
||||
const std::string& avsGateway,
|
||||
std::shared_ptr<MessageConsumerInterface> messageConsumerInterface,
|
||||
std::shared_ptr<TransportObserverInterface> transportObserverInterface) override;
|
||||
std::shared_ptr<TransportObserverInterface> transportObserverInterface,
|
||||
std::shared_ptr<SynchronizedMessageRequestQueue> sharedMessageRequestQueue) override;
|
||||
/// @}
|
||||
|
||||
/**
|
||||
|
@ -67,6 +71,9 @@ private:
|
|||
|
||||
/// Save a pointer to the object used to create instances of the PostConnectInterface.
|
||||
std::shared_ptr<PostConnectFactoryInterface> m_postConnectFactory;
|
||||
|
||||
/// The metric recorder.
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> m_metricRecorder;
|
||||
};
|
||||
|
||||
} // namespace acl
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2016-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -18,9 +18,10 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include <AVSCommon/AVS/MessageRequest.h>
|
||||
#include <AVSCommon/AVS/Attachment/AttachmentManager.h>
|
||||
#include <AVSCommon/AVS/MessageRequest.h>
|
||||
#include <AVSCommon/Utils/HTTP2/HTTP2MimeRequestSourceInterface.h>
|
||||
#include <AVSCommon/Utils/Metrics/MetricRecorderInterface.h>
|
||||
|
||||
#include "ACL/Transport/ExchangeHandler.h"
|
||||
#include "ACL/Transport/MessageConsumerInterface.h"
|
||||
|
@ -51,6 +52,7 @@ public:
|
|||
* @param messageRequest The MessageRequest to send.
|
||||
* @param messageConsumer Where to send messages.
|
||||
* @param attachmentManager Where to get attachments to write to.
|
||||
* @param metricRecorder The metric recorder.
|
||||
* @return A new MessageRequestHandler or nullptr if the operation fails.
|
||||
*/
|
||||
static std::shared_ptr<MessageRequestHandler> create(
|
||||
|
@ -58,7 +60,8 @@ public:
|
|||
const std::string& authToken,
|
||||
std::shared_ptr<avsCommon::avs::MessageRequest> messageRequest,
|
||||
std::shared_ptr<MessageConsumerInterface> messageConsumer,
|
||||
std::shared_ptr<avsCommon::avs::attachment::AttachmentManager> attachmentManager);
|
||||
std::shared_ptr<avsCommon::avs::attachment::AttachmentManager> attachmentManager,
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -67,11 +70,13 @@ private:
|
|||
* @param context The ExchangeContext in which this MessageRequest handler will operate.
|
||||
* @param authToken The token to use to authorize the request.
|
||||
* @param messageRequest The MessageRequest to send.
|
||||
* @param metricRecorder The metric recorder.
|
||||
*/
|
||||
MessageRequestHandler(
|
||||
std::shared_ptr<ExchangeHandlerContextInterface> context,
|
||||
const std::string& authToken,
|
||||
std::shared_ptr<avsCommon::avs::MessageRequest> messageRequest);
|
||||
std::shared_ptr<avsCommon::avs::MessageRequest> messageRequest,
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder);
|
||||
|
||||
/**
|
||||
* Notify the associated HTTP2Transport instance that the message request failed or was acknowledged by AVS.
|
||||
|
@ -116,13 +121,16 @@ private:
|
|||
/// Reader for current attachment (if any).
|
||||
std::shared_ptr<avsCommon::avs::MessageRequest::NamedReader> m_namedReader;
|
||||
|
||||
/// The metric recorder.
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> m_metricRecorder;
|
||||
|
||||
/// Whether acknowledge of the @c MessageRequest was reported.
|
||||
bool m_wasMessageRequestAcknowledgeReported;
|
||||
|
||||
/// Whether finish of the @c MessageRequest was reported.
|
||||
bool m_wasMessageRequestFinishedReported;
|
||||
|
||||
/// Response code received through @c onReciveResponseCode (or zero).
|
||||
/// Response code received through @c onReceiveResponseCode (or zero).
|
||||
long m_responseCode;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ALEXA_CLIENT_SDK_ACL_INCLUDE_ACL_TRANSPORT_MESSAGEREQUESTQUEUE_H_
|
||||
#define ALEXA_CLIENT_SDK_ACL_INCLUDE_ACL_TRANSPORT_MESSAGEREQUESTQUEUE_H_
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include <AVSCommon/AVS/MessageRequest.h>
|
||||
#include <AVSCommon/Utils/functional/hash.h>
|
||||
|
||||
#include "ACL/Transport/MessageRequestQueueInterface.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace acl {
|
||||
|
||||
/**
|
||||
* Class to manage @c MessageRequest send queues in HTTP2Transport.
|
||||
*
|
||||
* Note: This class is not thread safe. The user should ensure thread safety.
|
||||
*/
|
||||
class MessageRequestQueue : public MessageRequestQueueInterface {
|
||||
public:
|
||||
/// Helper structure to keep track of the SendQueue.
|
||||
struct MessageRequestQueueStruct {
|
||||
/// Indicates if the queue is waiting on a response.
|
||||
bool isQueueWaitingForResponse;
|
||||
|
||||
/// The queue used to send @c MessageRequest.
|
||||
std::deque<std::pair<
|
||||
std::chrono::time_point<std::chrono::steady_clock>,
|
||||
std::shared_ptr<avsCommon::avs::MessageRequest>>>
|
||||
queue;
|
||||
|
||||
MessageRequestQueueStruct() : isQueueWaitingForResponse{false} {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
MessageRequestQueue();
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~MessageRequestQueue() override;
|
||||
|
||||
/// Override MessageRequestQueueInterface methods
|
||||
/// @{
|
||||
void enqueueRequest(std::shared_ptr<avsCommon::avs::MessageRequest> messageRequest) override;
|
||||
avsCommon::utils::Optional<std::chrono::time_point<std::chrono::steady_clock>> peekRequestTime() override;
|
||||
std::shared_ptr<avsCommon::avs::MessageRequest> dequeueRequest() override;
|
||||
bool isMessageRequestAvailable() const override;
|
||||
void setWaitingFlagForQueue() override;
|
||||
void clearWaitingFlagForQueue() override;
|
||||
bool empty() const override;
|
||||
void clear() override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
/// Member to keep track of the current @c MessageRequests present.
|
||||
int m_size;
|
||||
|
||||
/// The struct that contains the message queue
|
||||
MessageRequestQueueStruct m_sendQueue;
|
||||
};
|
||||
|
||||
} // namespace acl
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
#endif // ALEXA_CLIENT_SDK_ACL_INCLUDE_ACL_TRANSPORT_MESSAGEREQUESTQUEUE_H_
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ALEXA_CLIENT_SDK_ACL_INCLUDE_ACL_TRANSPORT_MESSAGEREQUESTQUEUEINTERFACE_H_
|
||||
#define ALEXA_CLIENT_SDK_ACL_INCLUDE_ACL_TRANSPORT_MESSAGEREQUESTQUEUEINTERFACE_H_
|
||||
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <AVSCommon/AVS/MessageRequest.h>
|
||||
#include <AVSCommon/Utils/Optional.h>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace acl {
|
||||
|
||||
/**
|
||||
* An interface that abstracts the operations of a @c MessageRequestQueuesMap between the standard version
|
||||
* and the synchronized implementation.
|
||||
*/
|
||||
class MessageRequestQueueInterface {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~MessageRequestQueueInterface() = default;
|
||||
|
||||
/**
|
||||
* Enqueues the @c MessageRequest to the corresponding send queue based on the send queue type.
|
||||
* If send queue type is not present, a new queue is created before enqueuing the request.
|
||||
*/
|
||||
virtual void enqueueRequest(std::shared_ptr<avsCommon::avs::MessageRequest> messageRequest) = 0;
|
||||
|
||||
/**
|
||||
* Peek at the next item in the queue and retrieve the time that the request was queued.
|
||||
*
|
||||
* @return The time that the next request (if any) was queued.
|
||||
*/
|
||||
virtual avsCommon::utils::Optional<std::chrono::time_point<std::chrono::steady_clock>> peekRequestTime() = 0;
|
||||
|
||||
/**
|
||||
* Dequeues the next available @c MessageRequest by taking into account if the queue is waiting for
|
||||
* a response. This method keeps track of the queue being processed and once a request from the queue
|
||||
* is dequeued moves it to the next queue. It also loops back to the starting queue at the end and exits
|
||||
* the loop if a valid MessageRequest is found or if it reaches the place it started.
|
||||
*
|
||||
* @return @c MessageRequest if an available, else return nullptr.
|
||||
*/
|
||||
virtual std::shared_ptr<avsCommon::avs::MessageRequest> dequeueRequest() = 0;
|
||||
|
||||
/**
|
||||
* This method checks if there is a @c MessageRequest available to be sent.
|
||||
*
|
||||
* @return true if @c MessageRequest is available to be sent, else false.
|
||||
*/
|
||||
virtual bool isMessageRequestAvailable() const = 0;
|
||||
|
||||
/**
|
||||
* Sets the waiting flag for the queue specified by the given send queue type.
|
||||
*
|
||||
* @param sendQueueType the send queue type of the queue to set the waiting flag on.
|
||||
*/
|
||||
virtual void setWaitingFlagForQueue() = 0;
|
||||
|
||||
/**
|
||||
* Clear the waiting flag for the queue specified by the given send queue type.
|
||||
*
|
||||
* @param sendQueueType the send queue type of the queue to clear the waiting flag on.
|
||||
*/
|
||||
virtual void clearWaitingFlagForQueue() = 0;
|
||||
|
||||
/**
|
||||
* Checks if there are any @c MessageRequests.
|
||||
*
|
||||
* @return true if there are no messageRequests in the queue, else false.
|
||||
*/
|
||||
virtual bool empty() const = 0;
|
||||
|
||||
/**
|
||||
* Clears all the @c MessageRequests along with the corresponding queues.
|
||||
*/
|
||||
virtual void clear() = 0;
|
||||
};
|
||||
|
||||
} // namespace acl
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
#endif // ALEXA_CLIENT_SDK_ACL_INCLUDE_ACL_TRANSPORT_MESSAGEREQUESTQUEUEINTERFACE_H_
|
|
@ -33,6 +33,7 @@
|
|||
#include "ACL/Transport/TransportFactoryInterface.h"
|
||||
#include "ACL/Transport/TransportInterface.h"
|
||||
#include "ACL/Transport/TransportObserverInterface.h"
|
||||
#include "ACL/Transport/SynchronizedMessageRequestQueue.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace acl {
|
||||
|
@ -202,6 +203,9 @@ private:
|
|||
/// The transport factory.
|
||||
std::shared_ptr<TransportFactoryInterface> m_transportFactory;
|
||||
|
||||
/// The synchonized queue of messages to send that is shared between transports.
|
||||
std::shared_ptr<SynchronizedMessageRequestQueue> m_requestQueue;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Executor to perform asynchronous operations:
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ALEXA_CLIENT_SDK_ACL_INCLUDE_ACL_TRANSPORT_SYNCHRONIZEDMESSAGEREQUESTQUEUE_H_
|
||||
#define ALEXA_CLIENT_SDK_ACL_INCLUDE_ACL_TRANSPORT_SYNCHRONIZEDMESSAGEREQUESTQUEUE_H_
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <AVSCommon/AVS/MessageRequest.h>
|
||||
#include <AVSCommon/Utils/functional/hash.h>
|
||||
#include <ACL/Transport/MessageRequestQueue.h>
|
||||
#include "ACL/Transport/MessageRequestQueueInterface.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace acl {
|
||||
|
||||
/**
|
||||
* Class to manage @c MessageRequest send queue that is shared between instances of HTTP2Transport.
|
||||
*/
|
||||
class SynchronizedMessageRequestQueue : public MessageRequestQueueInterface {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
SynchronizedMessageRequestQueue() = default;
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~SynchronizedMessageRequestQueue() override;
|
||||
|
||||
/// Override MessageRequestQueueInterface methods
|
||||
/// @{
|
||||
void enqueueRequest(std::shared_ptr<avsCommon::avs::MessageRequest> messageRequest) override;
|
||||
avsCommon::utils::Optional<std::chrono::time_point<std::chrono::steady_clock>> peekRequestTime() override;
|
||||
std::shared_ptr<avsCommon::avs::MessageRequest> dequeueRequest() override;
|
||||
bool isMessageRequestAvailable() const override;
|
||||
void setWaitingFlagForQueue() override;
|
||||
void clearWaitingFlagForQueue() override;
|
||||
bool empty() const override;
|
||||
void clear() override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
MessageRequestQueue m_requestQueue;
|
||||
};
|
||||
|
||||
} // namespace acl
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
#endif // ALEXA_CLIENT_SDK_ACL_INCLUDE_ACL_TRANSPORT_SYNCHRONIZEDMESSAGEREQUESTQUEUE_H_
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -28,6 +28,11 @@ public:
|
|||
|
||||
/// Retry Timer Object for transport.
|
||||
static avsCommon::utils::RetryTimer RETRY_TIMER;
|
||||
|
||||
/// Static function member to get RETRY_TIMER
|
||||
static avsCommon::utils::RetryTimer getRetryTimer() {
|
||||
return RETRY_TIMER;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace acl
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -25,6 +25,7 @@
|
|||
#include "ACL/Transport/TransportInterface.h"
|
||||
#include "ACL/Transport/MessageConsumerInterface.h"
|
||||
#include "ACL/Transport/TransportObserverInterface.h"
|
||||
#include "ACL/Transport/SynchronizedMessageRequestQueue.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace acl {
|
||||
|
@ -38,9 +39,11 @@ public:
|
|||
* Creates a new transport.
|
||||
*
|
||||
* @param authDelegate The AuthDelegateInterface to use for authentication and authorization with AVS.
|
||||
* @param attachmentManager The attachment manager that manages the attachments.
|
||||
* @param avsGateway The URL for the AVS server we will connect to.
|
||||
* @param messageConsumerInterface The object which should be notified on messages which arrive from AVS.
|
||||
* @param transportObserverInterface A pointer to the transport observer the new transport should notify.
|
||||
* @param sharedRequestQueue Request queue shared by all instances of TransportInterface.
|
||||
* @return A new MessageRouter object.
|
||||
*/
|
||||
virtual std::shared_ptr<TransportInterface> createTransport(
|
||||
|
@ -48,7 +51,8 @@ public:
|
|||
std::shared_ptr<avsCommon::avs::attachment::AttachmentManager> attachmentManager,
|
||||
const std::string& avsGateway,
|
||||
std::shared_ptr<MessageConsumerInterface> messageConsumerInterface,
|
||||
std::shared_ptr<TransportObserverInterface> transportObserverInterface) = 0;
|
||||
std::shared_ptr<TransportObserverInterface> transportObserverInterface,
|
||||
std::shared_ptr<SynchronizedMessageRequestQueue> sharedMessageRequestQueue) = 0;
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -58,11 +58,9 @@ public:
|
|||
virtual bool isConnected() = 0;
|
||||
|
||||
/**
|
||||
* Sends an message request. This call blocks until the message can be sent.
|
||||
*
|
||||
* @param request The requested message.
|
||||
* A message request has been added to the shared synchronized queue and is ready to be read.
|
||||
*/
|
||||
virtual void send(std::shared_ptr<avsCommon::avs::MessageRequest> request) = 0;
|
||||
virtual void onRequestEnqueued() = 0;
|
||||
|
||||
/**
|
||||
* Deleted copy constructor
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -119,6 +119,7 @@ bool DownchannelHandler::onReceiveResponseCode(long responseCode) {
|
|||
case HTTPResponseCode::REDIRECTION_PERMANENT_REDIRECT:
|
||||
case HTTPResponseCode::CLIENT_ERROR_BAD_REQUEST:
|
||||
case HTTPResponseCode::SERVER_ERROR_INTERNAL:
|
||||
case HTTPResponseCode::SERVER_ERROR_NOT_IMPLEMENTED:
|
||||
break;
|
||||
case HTTPResponseCode::SUCCESS_OK:
|
||||
m_context->onDownchannelConnected();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2016-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2016-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -13,6 +13,7 @@
|
|||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <random>
|
||||
|
@ -59,6 +60,9 @@ static const int MAX_MESSAGE_HANDLERS = MAX_STREAMS - 2;
|
|||
/// Timeout to send a ping to AVS if there has not been any other acitivity on the connection.
|
||||
static std::chrono::minutes INACTIVITY_TIMEOUT{5};
|
||||
|
||||
/// Max time a @c MessageRequest should linger unprocessed before it should be consider TIMEDOUT.
|
||||
static const std::chrono::seconds MESSAGE_QUEUE_TIMEOUT = std::chrono::seconds(15);
|
||||
|
||||
/**
|
||||
* Write a @c HTTP2Transport::State value to an @c ostream as a string.
|
||||
*
|
||||
|
@ -101,7 +105,9 @@ std::shared_ptr<HTTP2Transport> HTTP2Transport::create(
|
|||
std::shared_ptr<AttachmentManager> attachmentManager,
|
||||
std::shared_ptr<TransportObserverInterface> transportObserver,
|
||||
std::shared_ptr<PostConnectFactoryInterface> postConnectFactory,
|
||||
Configuration configuration) {
|
||||
std::shared_ptr<SynchronizedMessageRequestQueue> sharedRequestQueue,
|
||||
Configuration configuration,
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder) {
|
||||
ACSDK_DEBUG5(LX(__func__)
|
||||
.d("authDelegate", authDelegate.get())
|
||||
.d("avsGateway", avsGateway)
|
||||
|
@ -109,7 +115,8 @@ std::shared_ptr<HTTP2Transport> HTTP2Transport::create(
|
|||
.d("messageConsumer", messageConsumer.get())
|
||||
.d("attachmentManager", attachmentManager.get())
|
||||
.d("transportObserver", transportObserver.get())
|
||||
.d("postConnectFactory", postConnectFactory.get()));
|
||||
.d("postConnectFactory", postConnectFactory.get())
|
||||
.d("sharedRequestQueue", sharedRequestQueue.get()));
|
||||
|
||||
if (!authDelegate) {
|
||||
ACSDK_ERROR(LX("createFailed").d("reason", "nullAuthDelegate"));
|
||||
|
@ -141,15 +148,22 @@ std::shared_ptr<HTTP2Transport> HTTP2Transport::create(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!sharedRequestQueue) {
|
||||
ACSDK_ERROR(LX("createFailed").d("reason", "nullSharedRequestQueue"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto transport = std::shared_ptr<HTTP2Transport>(new HTTP2Transport(
|
||||
authDelegate,
|
||||
std::move(authDelegate),
|
||||
avsGateway,
|
||||
http2Connection,
|
||||
messageConsumer,
|
||||
attachmentManager,
|
||||
transportObserver,
|
||||
postConnectFactory,
|
||||
configuration));
|
||||
std::move(http2Connection),
|
||||
std::move(messageConsumer),
|
||||
std::move(attachmentManager),
|
||||
std::move(transportObserver),
|
||||
std::move(postConnectFactory),
|
||||
std::move(sharedRequestQueue),
|
||||
configuration,
|
||||
std::move(metricRecorder)));
|
||||
|
||||
return transport;
|
||||
}
|
||||
|
@ -162,28 +176,23 @@ HTTP2Transport::HTTP2Transport(
|
|||
std::shared_ptr<AttachmentManager> attachmentManager,
|
||||
std::shared_ptr<TransportObserverInterface> transportObserver,
|
||||
std::shared_ptr<PostConnectFactoryInterface> postConnectFactory,
|
||||
Configuration configuration) :
|
||||
std::shared_ptr<SynchronizedMessageRequestQueue> sharedRequestQueue,
|
||||
Configuration configuration,
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder) :
|
||||
m_metricRecorder{std::move(metricRecorder)},
|
||||
m_state{State::INIT},
|
||||
m_authDelegate{authDelegate},
|
||||
m_authDelegate{std::move(authDelegate)},
|
||||
m_avsGateway{avsGateway},
|
||||
m_http2Connection{http2Connection},
|
||||
m_messageConsumer{messageConsumer},
|
||||
m_attachmentManager{attachmentManager},
|
||||
m_postConnectFactory{postConnectFactory},
|
||||
m_http2Connection{std::move(http2Connection)},
|
||||
m_messageConsumer{std::move(messageConsumer)},
|
||||
m_attachmentManager{std::move(attachmentManager)},
|
||||
m_postConnectFactory{std::move(postConnectFactory)},
|
||||
m_sharedRequestQueue{std::move(sharedRequestQueue)},
|
||||
m_connectRetryCount{0},
|
||||
m_isMessageHandlerAwaitingResponse{false},
|
||||
m_countOfUnfinishedMessageHandlers{0},
|
||||
m_postConnected{false},
|
||||
m_configuration{configuration},
|
||||
m_disconnectReason{ConnectionStatusObserverInterface::ChangedReason::NONE} {
|
||||
ACSDK_DEBUG7(LX(__func__)
|
||||
.d("authDelegate", authDelegate.get())
|
||||
.d("avsGateway", avsGateway)
|
||||
.d("http2Connection", http2Connection.get())
|
||||
.d("messageConsumer", messageConsumer.get())
|
||||
.d("attachmentManager", attachmentManager.get())
|
||||
.d("transportObserver", transportObserver.get())
|
||||
.d("postConnectFactory", postConnectFactory.get()));
|
||||
m_observers.insert(transportObserver);
|
||||
}
|
||||
|
||||
|
@ -250,14 +259,43 @@ bool HTTP2Transport::isConnected() {
|
|||
return State::CONNECTED == m_state;
|
||||
}
|
||||
|
||||
void HTTP2Transport::send(std::shared_ptr<MessageRequest> request) {
|
||||
void HTTP2Transport::onRequestEnqueued() {
|
||||
ACSDK_DEBUG7(LX(__func__));
|
||||
enqueueRequest(request, false);
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_wakeEvent.notify_all();
|
||||
}
|
||||
|
||||
void HTTP2Transport::sendPostConnectMessage(std::shared_ptr<MessageRequest> request) {
|
||||
ACSDK_DEBUG7(LX(__func__));
|
||||
enqueueRequest(request, true);
|
||||
if (!request) {
|
||||
ACSDK_ERROR(LX("enqueueRequestFailed").d("reason", "nullRequest"));
|
||||
}
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
bool allowed = false;
|
||||
switch (m_state) {
|
||||
case State::INIT:
|
||||
case State::AUTHORIZING:
|
||||
case State::CONNECTING:
|
||||
case State::WAITING_TO_RETRY_CONNECTING:
|
||||
case State::POST_CONNECTING:
|
||||
allowed = true;
|
||||
break;
|
||||
case State::CONNECTED:
|
||||
case State::SERVER_SIDE_DISCONNECT:
|
||||
case State::DISCONNECTING:
|
||||
case State::SHUTDOWN:
|
||||
allowed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (allowed) {
|
||||
m_requestQueue.enqueueRequest(request);
|
||||
m_wakeEvent.notify_all();
|
||||
} else {
|
||||
ACSDK_ERROR(LX("enqueueRequestFailed").d("reason", "notInAllowedState").d("m_state", m_state));
|
||||
lock.unlock();
|
||||
request->sendCompleted(MessageRequestObserverInterface::Status::NOT_CONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
void HTTP2Transport::onPostConnected() {
|
||||
|
@ -398,7 +436,7 @@ void HTTP2Transport::onDownchannelFinished() {
|
|||
|
||||
void HTTP2Transport::onMessageRequestSent() {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_isMessageHandlerAwaitingResponse = true;
|
||||
m_sharedRequestQueue->setWaitingFlagForQueue();
|
||||
m_countOfUnfinishedMessageHandlers++;
|
||||
ACSDK_DEBUG7(LX(__func__).d("countOfUnfinishedMessageHandlers", m_countOfUnfinishedMessageHandlers));
|
||||
}
|
||||
|
@ -415,7 +453,7 @@ void HTTP2Transport::onMessageRequestTimeout() {
|
|||
void HTTP2Transport::onMessageRequestAcknowledged() {
|
||||
ACSDK_DEBUG7(LX(__func__));
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_isMessageHandlerAwaitingResponse = false;
|
||||
m_sharedRequestQueue->clearWaitingFlagForQueue();
|
||||
m_wakeEvent.notify_all();
|
||||
}
|
||||
|
||||
|
@ -465,8 +503,13 @@ std::string HTTP2Transport::getAVSGateway() {
|
|||
return m_avsGateway;
|
||||
}
|
||||
|
||||
void HTTP2Transport::onGoawayReceived() {
|
||||
ACSDK_DEBUG5(LX(__func__));
|
||||
}
|
||||
|
||||
void HTTP2Transport::mainLoop() {
|
||||
ACSDK_DEBUG7(LX(__func__));
|
||||
m_http2Connection->addObserver(shared_from_this());
|
||||
|
||||
m_postConnect = m_postConnectFactory->createPostConnect();
|
||||
if (!m_postConnect || !m_postConnect->doPostConnect(shared_from_this(), shared_from_this())) {
|
||||
|
@ -526,55 +569,46 @@ HTTP2Transport::State HTTP2Transport::handleAuthorizing() {
|
|||
|
||||
m_authDelegate->addAuthObserver(shared_from_this());
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_wakeEvent.wait(lock, [this]() { return m_state != State::AUTHORIZING; });
|
||||
return m_state;
|
||||
return monitorSharedQueueWhileWaiting(State::AUTHORIZING);
|
||||
}
|
||||
|
||||
HTTP2Transport::State HTTP2Transport::handleConnecting() {
|
||||
ACSDK_DEBUG5(LX(__func__));
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
auto authToken = m_authDelegate->getAuthToken();
|
||||
|
||||
while (State::CONNECTING == m_state) {
|
||||
lock.unlock();
|
||||
|
||||
auto authToken = m_authDelegate->getAuthToken();
|
||||
|
||||
if (authToken.empty()) {
|
||||
setState(
|
||||
State::WAITING_TO_RETRY_CONNECTING, ConnectionStatusObserverInterface::ChangedReason::INVALID_AUTH);
|
||||
break;
|
||||
}
|
||||
|
||||
auto downchannelHandler =
|
||||
DownchannelHandler::create(shared_from_this(), authToken, m_messageConsumer, m_attachmentManager);
|
||||
lock.lock();
|
||||
|
||||
if (!downchannelHandler) {
|
||||
ACSDK_ERROR(LX("handleConnectingFailed").d("reason", "createDownchannelHandlerFailed"));
|
||||
setStateLocked(
|
||||
State::WAITING_TO_RETRY_CONNECTING, ConnectionStatusObserverInterface::ChangedReason::INTERNAL_ERROR);
|
||||
return m_state;
|
||||
}
|
||||
|
||||
while (State::CONNECTING == m_state) {
|
||||
m_wakeEvent.wait(lock);
|
||||
}
|
||||
if (authToken.empty()) {
|
||||
ACSDK_DEBUG0(LX("Empty AuthToken"));
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
setStateLocked(
|
||||
State::WAITING_TO_RETRY_CONNECTING, ConnectionStatusObserverInterface::ChangedReason::INVALID_AUTH);
|
||||
return m_state;
|
||||
}
|
||||
|
||||
return m_state;
|
||||
auto downchannelHandler =
|
||||
DownchannelHandler::create(shared_from_this(), authToken, m_messageConsumer, m_attachmentManager);
|
||||
|
||||
if (!downchannelHandler) {
|
||||
ACSDK_ERROR(LX("handleConnectingFailed").d("reason", "createDownchannelHandlerFailed"));
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
setStateLocked(
|
||||
State::WAITING_TO_RETRY_CONNECTING, ConnectionStatusObserverInterface::ChangedReason::INTERNAL_ERROR);
|
||||
return m_state;
|
||||
}
|
||||
|
||||
return monitorSharedQueueWhileWaiting(State::CONNECTING);
|
||||
}
|
||||
|
||||
HTTP2Transport::State HTTP2Transport::handleWaitingToRetryConnecting() {
|
||||
ACSDK_DEBUG7(LX(__func__));
|
||||
|
||||
std::chrono::milliseconds timeout = TransportDefines::RETRY_TIMER.calculateTimeToRetry(m_connectRetryCount);
|
||||
auto timeout = TransportDefines::getRetryTimer().calculateTimeToRetry(m_connectRetryCount);
|
||||
ACSDK_DEBUG7(
|
||||
LX("handleConnectingWaitingToRetry").d("connectRetryCount", m_connectRetryCount).d("timeout", timeout.count()));
|
||||
m_connectRetryCount++;
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_wakeEvent.wait_for(lock, timeout, [this] { return m_state != State::WAITING_TO_RETRY_CONNECTING; });
|
||||
|
||||
auto wakeTime = std::chrono::steady_clock::now() + timeout;
|
||||
monitorSharedQueueWhileWaiting(State::WAITING_TO_RETRY_CONNECTING, wakeTime);
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (State::WAITING_TO_RETRY_CONNECTING == m_state) {
|
||||
setStateLocked(State::CONNECTING, ConnectionStatusObserverInterface::ChangedReason::NONE);
|
||||
}
|
||||
|
@ -587,7 +621,7 @@ HTTP2Transport::State HTTP2Transport::handlePostConnecting() {
|
|||
setState(State::CONNECTED, ConnectionStatusObserverInterface::ChangedReason::SUCCESS);
|
||||
return State::CONNECTED;
|
||||
}
|
||||
return sendMessagesAndPings(State::POST_CONNECTING);
|
||||
return sendMessagesAndPings(State::POST_CONNECTING, m_requestQueue);
|
||||
}
|
||||
|
||||
HTTP2Transport::State HTTP2Transport::handleConnected() {
|
||||
|
@ -596,7 +630,7 @@ HTTP2Transport::State HTTP2Transport::handleConnected() {
|
|||
m_postConnect.reset();
|
||||
}
|
||||
notifyObserversOnConnected();
|
||||
return sendMessagesAndPings(State::CONNECTED);
|
||||
return sendMessagesAndPings(State::CONNECTED, *m_sharedRequestQueue);
|
||||
}
|
||||
|
||||
HTTP2Transport::State HTTP2Transport::handleServerSideDisconnect() {
|
||||
|
@ -621,12 +655,19 @@ HTTP2Transport::State HTTP2Transport::handleShutdown() {
|
|||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
for (auto request : m_requestQueue) {
|
||||
request->sendCompleted(MessageRequestObserverInterface::Status::NOT_CONNECTED);
|
||||
|
||||
// Flags are stored in the shared queue but the local request queue is drained.
|
||||
m_sharedRequestQueue->clearWaitingFlagForQueue();
|
||||
while (!m_requestQueue.empty()) {
|
||||
auto request = m_requestQueue.dequeueRequest();
|
||||
if (request != nullptr) {
|
||||
request->sendCompleted(MessageRequestObserverInterface::Status::NOT_CONNECTED);
|
||||
}
|
||||
}
|
||||
m_requestQueue.clear();
|
||||
}
|
||||
|
||||
m_http2Connection->removeObserver(shared_from_this());
|
||||
m_http2Connection->disconnect();
|
||||
|
||||
notifyObserversOnDisconnect(m_disconnectReason);
|
||||
|
@ -634,51 +675,53 @@ HTTP2Transport::State HTTP2Transport::handleShutdown() {
|
|||
return State::SHUTDOWN;
|
||||
}
|
||||
|
||||
void HTTP2Transport::enqueueRequest(std::shared_ptr<avsCommon::avs::MessageRequest> request, bool beforeConnected) {
|
||||
ACSDK_DEBUG7(LX(__func__).d("beforeConnected", beforeConnected));
|
||||
HTTP2Transport::State HTTP2Transport::monitorSharedQueueWhileWaiting(
|
||||
alexaClientSDK::acl::HTTP2Transport::State whileState,
|
||||
std::chrono::time_point<std::chrono::steady_clock> maxWakeTime) {
|
||||
while (true) {
|
||||
auto wakeTime = maxWakeTime;
|
||||
|
||||
if (!request) {
|
||||
ACSDK_ERROR(LX("enqueueRequestFailed").d("reason", "nullRequest"));
|
||||
}
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
bool allowed = false;
|
||||
switch (m_state) {
|
||||
case State::INIT:
|
||||
case State::AUTHORIZING:
|
||||
case State::CONNECTING:
|
||||
case State::WAITING_TO_RETRY_CONNECTING:
|
||||
case State::POST_CONNECTING:
|
||||
allowed = beforeConnected;
|
||||
break;
|
||||
case State::CONNECTED:
|
||||
allowed = !beforeConnected;
|
||||
break;
|
||||
case State::SERVER_SIDE_DISCONNECT:
|
||||
case State::DISCONNECTING:
|
||||
case State::SHUTDOWN:
|
||||
allowed = false;
|
||||
break;
|
||||
}
|
||||
while (true) {
|
||||
auto messageRequestTime = m_sharedRequestQueue->peekRequestTime();
|
||||
if (!messageRequestTime.hasValue()) {
|
||||
// No more messages queued, break out to wait to connect.
|
||||
break;
|
||||
}
|
||||
|
||||
if (allowed) {
|
||||
m_requestQueue.push_back(request);
|
||||
m_wakeEvent.notify_all();
|
||||
} else {
|
||||
lock.unlock();
|
||||
ACSDK_ERROR(LX("enqueueRequestFailed").d("reason", "notInAllowedState").d("m_state", m_state));
|
||||
request->sendCompleted(MessageRequestObserverInterface::Status::NOT_CONNECTED);
|
||||
auto messageTimeoutTime = messageRequestTime.value() + MESSAGE_QUEUE_TIMEOUT;
|
||||
if (messageTimeoutTime > std::chrono::steady_clock::now()) {
|
||||
// Next message has not timed out, break out to wait to connect.
|
||||
wakeTime = std::min(messageTimeoutTime, wakeTime);
|
||||
break;
|
||||
}
|
||||
|
||||
auto request = m_sharedRequestQueue->dequeueRequest();
|
||||
request->sendCompleted(MessageRequestObserverInterface::Status::TIMEDOUT);
|
||||
}
|
||||
|
||||
auto messageRequestTime = m_sharedRequestQueue->peekRequestTime();
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_wakeEvent.wait_until(lock, wakeTime, [this, whileState, messageRequestTime] {
|
||||
return m_state != whileState || m_sharedRequestQueue->peekRequestTime() != messageRequestTime;
|
||||
});
|
||||
|
||||
if (whileState != m_state || std::chrono::steady_clock::now() >= maxWakeTime) {
|
||||
return m_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HTTP2Transport::State HTTP2Transport::sendMessagesAndPings(alexaClientSDK::acl::HTTP2Transport::State whileState) {
|
||||
HTTP2Transport::State HTTP2Transport::sendMessagesAndPings(
|
||||
alexaClientSDK::acl::HTTP2Transport::State whileState,
|
||||
MessageRequestQueueInterface& requestQueue) {
|
||||
ACSDK_DEBUG7(LX(__func__).d("whileState", whileState));
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
auto canSendMessage = [this] {
|
||||
auto canSendMessage = [this, &requestQueue] {
|
||||
return (
|
||||
!m_isMessageHandlerAwaitingResponse && !m_requestQueue.empty() &&
|
||||
(m_countOfUnfinishedMessageHandlers < MAX_MESSAGE_HANDLERS));
|
||||
requestQueue.isMessageRequestAvailable() && (m_countOfUnfinishedMessageHandlers < MAX_MESSAGE_HANDLERS));
|
||||
};
|
||||
|
||||
auto wakePredicate = [this, whileState, canSendMessage] {
|
||||
|
@ -702,15 +745,19 @@ HTTP2Transport::State HTTP2Transport::sendMessagesAndPings(alexaClientSDK::acl::
|
|||
}
|
||||
|
||||
if (canSendMessage()) {
|
||||
auto messageRequest = m_requestQueue.front();
|
||||
m_requestQueue.pop_front();
|
||||
auto messageRequest = requestQueue.dequeueRequest();
|
||||
|
||||
lock.unlock();
|
||||
|
||||
auto authToken = m_authDelegate->getAuthToken();
|
||||
if (!authToken.empty()) {
|
||||
auto handler = MessageRequestHandler::create(
|
||||
shared_from_this(), authToken, messageRequest, m_messageConsumer, m_attachmentManager);
|
||||
shared_from_this(),
|
||||
authToken,
|
||||
messageRequest,
|
||||
m_messageConsumer,
|
||||
m_attachmentManager,
|
||||
m_metricRecorder);
|
||||
if (!handler) {
|
||||
messageRequest->sendCompleted(MessageRequestObserverInterface::Status::INTERNAL_ERROR);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -31,7 +31,8 @@ std::shared_ptr<TransportInterface> HTTP2TransportFactory::createTransport(
|
|||
std::shared_ptr<AttachmentManager> attachmentManager,
|
||||
const std::string& avsGateway,
|
||||
std::shared_ptr<MessageConsumerInterface> messageConsumerInterface,
|
||||
std::shared_ptr<TransportObserverInterface> transportObserverInterface) {
|
||||
std::shared_ptr<TransportObserverInterface> transportObserverInterface,
|
||||
std::shared_ptr<SynchronizedMessageRequestQueue> sharedMessageRequestQueue) {
|
||||
auto connection = m_connectionFactory->createHTTP2Connection();
|
||||
if (!connection) {
|
||||
return nullptr;
|
||||
|
@ -44,14 +45,19 @@ std::shared_ptr<TransportInterface> HTTP2TransportFactory::createTransport(
|
|||
messageConsumerInterface,
|
||||
attachmentManager,
|
||||
transportObserverInterface,
|
||||
m_postConnectFactory);
|
||||
m_postConnectFactory,
|
||||
sharedMessageRequestQueue,
|
||||
HTTP2Transport::Configuration(),
|
||||
m_metricRecorder);
|
||||
}
|
||||
|
||||
HTTP2TransportFactory::HTTP2TransportFactory(
|
||||
std::shared_ptr<avsCommon::utils::http2::HTTP2ConnectionFactoryInterface> connectionFactory,
|
||||
std::shared_ptr<PostConnectFactoryInterface> postConnectFactory) :
|
||||
m_connectionFactory{connectionFactory},
|
||||
m_postConnectFactory{postConnectFactory} {
|
||||
std::shared_ptr<PostConnectFactoryInterface> postConnectFactory,
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder) :
|
||||
m_connectionFactory{std::move(connectionFactory)},
|
||||
m_postConnectFactory{std::move(postConnectFactory)},
|
||||
m_metricRecorder{std::move(metricRecorder)} {
|
||||
}
|
||||
|
||||
} // namespace acl
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -21,6 +21,9 @@
|
|||
#include <AVSCommon/Utils/HTTP2/HTTP2MimeRequestEncoder.h>
|
||||
#include <AVSCommon/Utils/HTTP2/HTTP2MimeResponseDecoder.h>
|
||||
#include <AVSCommon/Utils/Logger/Logger.h>
|
||||
#include <AVSCommon/Utils/Metrics/DataPointStringBuilder.h>
|
||||
#include <AVSCommon/Utils/Metrics/DataPointCounterBuilder.h>
|
||||
#include <AVSCommon/Utils/Metrics/MetricEventBuilder.h>
|
||||
|
||||
#include "ACL/Transport/HTTP2Transport.h"
|
||||
#include "ACL/Transport/MimeResponseSink.h"
|
||||
|
@ -33,6 +36,7 @@ using namespace avsCommon::avs::attachment;
|
|||
using namespace avsCommon::sdkInterfaces;
|
||||
using namespace avsCommon::utils::http;
|
||||
using namespace avsCommon::utils::http2;
|
||||
using namespace avsCommon::utils::metrics;
|
||||
|
||||
/// URL to send events to
|
||||
const static std::string AVS_EVENT_URL_PATH_EXTENSION = "/v20160207/events";
|
||||
|
@ -63,6 +67,24 @@ static const std::string MESSAGEREQUEST_ID_PREFIX = "AVSEvent-";
|
|||
/// String to identify log entries originating from this file.
|
||||
static const std::string TAG("MessageRequestHandler");
|
||||
|
||||
/// Prefix used to identify metrics published by this module.
|
||||
static const std::string ACL_METRIC_SOURCE_PREFIX = "ACL-";
|
||||
|
||||
/// Metric identifier for send mime data error
|
||||
static const std::string SEND_DATA_ERROR = "ERROR.SEND_DATA_ERROR";
|
||||
|
||||
/// Read status tag
|
||||
static const std::string READ_STATUS_TAG = "READ_STATUS";
|
||||
|
||||
/// Read overrun error
|
||||
static const std::string ERROR_READ_OVERRUN = "READ_OVERRUN";
|
||||
|
||||
/// Internal error
|
||||
static const std::string ERROR_INTERNAL = "INTERNAL_ERROR";
|
||||
|
||||
/// Send completed
|
||||
static const std::string SEND_COMPLETED = "SEND_COMPLETED";
|
||||
|
||||
/**
|
||||
* Create a LogEntry using this file's TAG and the specified event string.
|
||||
*
|
||||
|
@ -70,6 +92,26 @@ static const std::string TAG("MessageRequestHandler");
|
|||
*/
|
||||
#define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event)
|
||||
|
||||
/**
|
||||
* Capture metric for the last send data result.
|
||||
*
|
||||
* @param metricRecorder The metric recorder object.
|
||||
* @param count Number of errors.
|
||||
* @param readStatus The read status.
|
||||
*/
|
||||
static void collectSendDataResultMetric(
|
||||
const std::shared_ptr<MetricRecorderInterface>& metricRecorder,
|
||||
int count,
|
||||
const std::string& readStatus) {
|
||||
recordMetric(
|
||||
metricRecorder,
|
||||
MetricEventBuilder{}
|
||||
.setActivityName(ACL_METRIC_SOURCE_PREFIX + SEND_DATA_ERROR)
|
||||
.addDataPoint(DataPointCounterBuilder{}.setName(SEND_DATA_ERROR).increment(count).build())
|
||||
.addDataPoint(DataPointStringBuilder{}.setName(READ_STATUS_TAG).setValue(readStatus).build())
|
||||
.build());
|
||||
}
|
||||
|
||||
MessageRequestHandler::~MessageRequestHandler() {
|
||||
reportMessageRequestAcknowledged();
|
||||
reportMessageRequestFinished();
|
||||
|
@ -80,7 +122,8 @@ std::shared_ptr<MessageRequestHandler> MessageRequestHandler::create(
|
|||
const std::string& authToken,
|
||||
std::shared_ptr<avsCommon::avs::MessageRequest> messageRequest,
|
||||
std::shared_ptr<MessageConsumerInterface> messageConsumer,
|
||||
std::shared_ptr<avsCommon::avs::attachment::AttachmentManager> attachmentManager) {
|
||||
std::shared_ptr<avsCommon::avs::attachment::AttachmentManager> attachmentManager,
|
||||
std::shared_ptr<MetricRecorderInterface> metricRecorder) {
|
||||
ACSDK_DEBUG7(LX(__func__).d("context", context.get()).d("messageRequest", messageRequest.get()));
|
||||
|
||||
if (!context) {
|
||||
|
@ -93,7 +136,8 @@ std::shared_ptr<MessageRequestHandler> MessageRequestHandler::create(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<MessageRequestHandler> handler(new MessageRequestHandler(context, authToken, messageRequest));
|
||||
std::shared_ptr<MessageRequestHandler> handler(
|
||||
new MessageRequestHandler(context, authToken, messageRequest, std::move(metricRecorder)));
|
||||
|
||||
// Allow custom path extension, if provided by the sender of the MessageRequest
|
||||
|
||||
|
@ -126,13 +170,15 @@ std::shared_ptr<MessageRequestHandler> MessageRequestHandler::create(
|
|||
MessageRequestHandler::MessageRequestHandler(
|
||||
std::shared_ptr<ExchangeHandlerContextInterface> context,
|
||||
const std::string& authToken,
|
||||
std::shared_ptr<avsCommon::avs::MessageRequest> messageRequest) :
|
||||
std::shared_ptr<avsCommon::avs::MessageRequest> messageRequest,
|
||||
std::shared_ptr<MetricRecorderInterface> metricRecorder) :
|
||||
ExchangeHandler{context, authToken},
|
||||
m_messageRequest{messageRequest},
|
||||
m_json{messageRequest->getJsonContent()},
|
||||
m_jsonNext{m_json.c_str()},
|
||||
m_countOfJsonBytesLeft{m_json.size()},
|
||||
m_countOfPartsSent{0},
|
||||
m_metricRecorder{metricRecorder},
|
||||
m_wasMessageRequestAcknowledgeReported{false},
|
||||
m_wasMessageRequestFinishedReported{false},
|
||||
m_responseCode{0} {
|
||||
|
@ -219,11 +265,17 @@ HTTP2SendDataResult MessageRequestHandler::onSendMimePartData(char* bytes, size_
|
|||
// Stream consumed. Move on to next part.
|
||||
m_namedReader.reset();
|
||||
m_countOfPartsSent++;
|
||||
collectSendDataResultMetric(m_metricRecorder, 0, SEND_COMPLETED);
|
||||
return HTTP2SendDataResult::COMPLETE;
|
||||
|
||||
// Handle any attachment read errors.
|
||||
case AttachmentReader::ReadStatus::ERROR_OVERRUN:
|
||||
collectSendDataResultMetric(m_metricRecorder, 1, ERROR_READ_OVERRUN);
|
||||
// Stream failure. Abort sending the request.
|
||||
return HTTP2SendDataResult::ABORT;
|
||||
|
||||
case AttachmentReader::ReadStatus::ERROR_INTERNAL:
|
||||
collectSendDataResultMetric(m_metricRecorder, 1, ERROR_INTERNAL);
|
||||
// Stream failure. Abort sending the request.
|
||||
return HTTP2SendDataResult::ABORT;
|
||||
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#include <AVSCommon/AVS/MessageRequest.h>
|
||||
#include <AVSCommon/Utils/Logger/Logger.h>
|
||||
|
||||
#include "ACL/Transport/MessageRequestQueue.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace acl {
|
||||
|
||||
using namespace avsCommon::avs;
|
||||
|
||||
/// String to identify log entries originating from this file.
|
||||
static const std::string TAG("MessageRequestQueue");
|
||||
|
||||
static const std::string EMPTY_QUEUE_NAME = "";
|
||||
|
||||
/**
|
||||
* Create a LogEntry using this file's TAG and the specified event string.
|
||||
*
|
||||
* @param The event string for this @c LogEntry.
|
||||
*/
|
||||
#define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event)
|
||||
|
||||
MessageRequestQueue::MessageRequestQueue() : m_size{0} {
|
||||
}
|
||||
|
||||
MessageRequestQueue::~MessageRequestQueue() {
|
||||
clearWaitingFlagForQueue();
|
||||
clear();
|
||||
}
|
||||
|
||||
void MessageRequestQueue::enqueueRequest(std::shared_ptr<MessageRequest> messageRequest) {
|
||||
if (messageRequest != nullptr) {
|
||||
m_sendQueue.queue.push_back({std::chrono::steady_clock::now(), messageRequest});
|
||||
m_size++;
|
||||
} else {
|
||||
ACSDK_ERROR(LX("enqueueRequest").d("reason", "nullMessageRequest"));
|
||||
}
|
||||
}
|
||||
|
||||
avsCommon::utils::Optional<std::chrono::time_point<std::chrono::steady_clock>> MessageRequestQueue::peekRequestTime() {
|
||||
if (m_size > 0) {
|
||||
return m_sendQueue.queue.front().first;
|
||||
}
|
||||
|
||||
return avsCommon::utils::Optional<std::chrono::time_point<std::chrono::steady_clock>>();
|
||||
}
|
||||
|
||||
std::shared_ptr<MessageRequest> MessageRequestQueue::dequeueRequest() {
|
||||
std::shared_ptr<MessageRequest> messageRequest;
|
||||
|
||||
if (m_size > 0) {
|
||||
messageRequest = m_sendQueue.queue.front().second;
|
||||
m_sendQueue.queue.pop_front();
|
||||
m_size--;
|
||||
}
|
||||
return messageRequest;
|
||||
}
|
||||
|
||||
bool MessageRequestQueue::isMessageRequestAvailable() const {
|
||||
return !m_sendQueue.queue.empty() && !m_sendQueue.isQueueWaitingForResponse;
|
||||
}
|
||||
|
||||
void MessageRequestQueue::setWaitingFlagForQueue() {
|
||||
m_sendQueue.isQueueWaitingForResponse = true;
|
||||
}
|
||||
|
||||
void MessageRequestQueue::clearWaitingFlagForQueue() {
|
||||
m_sendQueue.isQueueWaitingForResponse = false;
|
||||
}
|
||||
|
||||
bool MessageRequestQueue::empty() const {
|
||||
return (0 == m_size);
|
||||
}
|
||||
|
||||
void MessageRequestQueue::clear() {
|
||||
m_sendQueue.queue.clear();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
} // namespace acl
|
||||
} // namespace alexaClientSDK
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2016-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2016-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -52,7 +52,8 @@ MessageRouter::MessageRouter(
|
|||
m_connectionReason{ConnectionStatusObserverInterface::ChangedReason::ACL_CLIENT_REQUEST},
|
||||
m_isEnabled{false},
|
||||
m_attachmentManager{attachmentManager},
|
||||
m_transportFactory{transportFactory} {
|
||||
m_transportFactory{transportFactory},
|
||||
m_requestQueue{std::make_shared<SynchronizedMessageRequestQueue>()} {
|
||||
}
|
||||
|
||||
MessageRouterInterface::ConnectionStatus MessageRouter::getConnectionStatus() {
|
||||
|
@ -82,6 +83,20 @@ void MessageRouter::enable() {
|
|||
|
||||
void MessageRouter::doShutdown() {
|
||||
disable();
|
||||
|
||||
// The above call will release all the transports. If m_requestQueue is non-empty once all of the transports
|
||||
// have been released, any outstanding MessageRequest instances must receive an onCompleted(NOT_CONNECTED)
|
||||
// notification.
|
||||
std::unique_lock<std::mutex> lock{m_connectionMutex};
|
||||
if (!m_requestQueue->empty()) {
|
||||
auto request = m_requestQueue->dequeueRequest();
|
||||
if (request != nullptr) {
|
||||
request->sendCompleted(MessageRequestObserverInterface::Status::NOT_CONNECTED);
|
||||
}
|
||||
m_requestQueue->clear();
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
m_executor.shutdown();
|
||||
}
|
||||
|
||||
|
@ -98,7 +113,8 @@ void MessageRouter::sendMessage(std::shared_ptr<MessageRequest> request) {
|
|||
}
|
||||
std::unique_lock<std::mutex> lock{m_connectionMutex};
|
||||
if (m_activeTransport) {
|
||||
m_activeTransport->send(request);
|
||||
m_requestQueue->enqueueRequest(request);
|
||||
m_activeTransport->onRequestEnqueued();
|
||||
} else {
|
||||
ACSDK_ERROR(LX("sendFailed").d("reason", "noActiveTransport"));
|
||||
request->sendCompleted(MessageRequestObserverInterface::Status::NOT_CONNECTED);
|
||||
|
@ -240,7 +256,7 @@ void MessageRouter::notifyObserverOnReceive(const std::string& contextId, const
|
|||
|
||||
void MessageRouter::createActiveTransportLocked() {
|
||||
auto transport = m_transportFactory->createTransport(
|
||||
m_authDelegate, m_attachmentManager, m_avsGateway, shared_from_this(), shared_from_this());
|
||||
m_authDelegate, m_attachmentManager, m_avsGateway, shared_from_this(), shared_from_this(), m_requestQueue);
|
||||
if (transport && transport->connect()) {
|
||||
m_transports.push_back(transport);
|
||||
m_activeTransport = transport;
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#include <AVSCommon/AVS/MessageRequest.h>
|
||||
#include <AVSCommon/Utils/Logger/Logger.h>
|
||||
|
||||
#include "ACL/Transport/SynchronizedMessageRequestQueue.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace acl {
|
||||
|
||||
using namespace avsCommon::avs;
|
||||
|
||||
/// String to identify log entries originating from this file.
|
||||
static const std::string TAG("SynchronizedMessageRequestQueue");
|
||||
|
||||
/**
|
||||
* Create a LogEntry using this file's TAG and the specified event string.
|
||||
*
|
||||
* @param The event string for this @c LogEntry.
|
||||
*/
|
||||
#define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event)
|
||||
|
||||
SynchronizedMessageRequestQueue::~SynchronizedMessageRequestQueue() {
|
||||
clearWaitingFlagForQueue();
|
||||
clear();
|
||||
}
|
||||
|
||||
void SynchronizedMessageRequestQueue::enqueueRequest(std::shared_ptr<MessageRequest> messageRequest) {
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
m_requestQueue.enqueueRequest(std::move(messageRequest));
|
||||
}
|
||||
|
||||
avsCommon::utils::Optional<std::chrono::time_point<std::chrono::steady_clock>> SynchronizedMessageRequestQueue::
|
||||
peekRequestTime() {
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
return m_requestQueue.peekRequestTime();
|
||||
}
|
||||
|
||||
std::shared_ptr<MessageRequest> SynchronizedMessageRequestQueue::dequeueRequest() {
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
return m_requestQueue.dequeueRequest();
|
||||
}
|
||||
|
||||
bool SynchronizedMessageRequestQueue::isMessageRequestAvailable() const {
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
return m_requestQueue.isMessageRequestAvailable();
|
||||
}
|
||||
|
||||
void SynchronizedMessageRequestQueue::setWaitingFlagForQueue() {
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
m_requestQueue.setWaitingFlagForQueue();
|
||||
}
|
||||
|
||||
void SynchronizedMessageRequestQueue::clearWaitingFlagForQueue() {
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
m_requestQueue.clearWaitingFlagForQueue();
|
||||
}
|
||||
|
||||
bool SynchronizedMessageRequestQueue::empty() const {
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
return m_requestQueue.empty();
|
||||
}
|
||||
|
||||
void SynchronizedMessageRequestQueue::clear() {
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
m_requestQueue.clear();
|
||||
}
|
||||
|
||||
} // namespace acl
|
||||
} // namespace alexaClientSDK
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
|
|
@ -2,9 +2,9 @@ add_subdirectory("Transport")
|
|||
|
||||
set(LIBRARIES ACL ${CMAKE_THREAD_LIBS_INIT} ACLTransportCommonTestLib)
|
||||
set(INCLUDE_PATH
|
||||
${AVSCommon_INCLUDE_DIRS}
|
||||
"${AVSCommon_INCLUDE_DIRS}"
|
||||
"${ACL_SOURCE_DIR}/include"
|
||||
"${AVSCommon_SOURCE_DIR}/AVS/test"
|
||||
"${AVSCommon_SOURCE_DIR}/SDKInterfaces/test"
|
||||
"${AVSCommon_SOURCE_DIR}/Utils/test")
|
||||
discover_unit_tests( "${INCLUDE_PATH}" "${LIBRARIES}")
|
||||
discover_unit_tests("${INCLUDE_PATH}" "${LIBRARIES}")
|
||||
|
|
|
@ -5,7 +5,8 @@ add_library(ACLTransportCommonTestLib
|
|||
MockHTTP2Request.cpp
|
||||
MockMimeResponseSink.cpp)
|
||||
target_include_directories(ACLTransportCommonTestLib PUBLIC
|
||||
"${ACL_SOURCE_DIR}/include" "${ACL_SOURCE_DIR}/test/Transport")
|
||||
"${ACL_SOURCE_DIR}/include"
|
||||
"${ACL_SOURCE_DIR}/test/Transport")
|
||||
target_link_libraries(ACLTransportCommonTestLib
|
||||
AVSCommon
|
||||
gtest_main
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -251,6 +251,15 @@ std::size_t MockHTTP2Connection::getMaxPostRequestsEnqueud() {
|
|||
return m_maxPostRequestsEnqueued;
|
||||
}
|
||||
|
||||
void MockHTTP2Connection::addObserver(std::shared_ptr<HTTP2ConnectionObserverInterface> observer) {
|
||||
std::lock_guard<std::mutex> lock{m_observersMutex};
|
||||
m_observers.insert(observer);
|
||||
}
|
||||
void MockHTTP2Connection::removeObserver(std::shared_ptr<HTTP2ConnectionObserverInterface> observer) {
|
||||
std::lock_guard<std::mutex> lock{m_observersMutex};
|
||||
m_observers.erase(observer);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace http2
|
||||
} // namespace utils
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -30,6 +30,7 @@
|
|||
#include <AVSCommon/Utils/PromiseFuturePair.h>
|
||||
#include <AVSCommon/Utils/HTTP/HttpResponseCode.h>
|
||||
#include <AVSCommon/Utils/HTTP2/HTTP2RequestConfig.h>
|
||||
#include <AVSCommon/Utils/Metrics/MockMetricRecorder.h>
|
||||
|
||||
#include "MockAuthDelegate.h"
|
||||
#include "MockHTTP2Connection.h"
|
||||
|
@ -39,6 +40,8 @@
|
|||
#include "MockPostConnectFactory.h"
|
||||
#include "MockTransportObserver.h"
|
||||
|
||||
#include "ACL/Transport/SynchronizedMessageRequestQueue.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace acl {
|
||||
namespace transport {
|
||||
|
@ -202,6 +205,12 @@ protected:
|
|||
/// The mock @c PostConnectInterface.
|
||||
std::shared_ptr<MockPostConnect> m_mockPostConnect;
|
||||
|
||||
/// The mock @c MetricRecorder.
|
||||
std::shared_ptr<metrics::test::MockMetricRecorder> m_mockMetricRecorder;
|
||||
|
||||
/// The message queue map.
|
||||
std::shared_ptr<SynchronizedMessageRequestQueue> m_synchronizedMessageRequestQueue;
|
||||
|
||||
/// A promise that the Auth Observer will be set.
|
||||
PromiseFuturePair<std::shared_ptr<AuthObserverInterface>> m_authObserverSet;
|
||||
|
||||
|
@ -253,7 +262,11 @@ void HTTP2TransportTest::SetUp() {
|
|||
m_mockTransportObserver = std::make_shared<NiceMock<MockTransportObserver>>();
|
||||
m_mockPostConnectFactory = std::make_shared<NiceMock<MockPostConnectFactory>>();
|
||||
m_mockPostConnect = std::make_shared<NiceMock<MockPostConnect>>();
|
||||
m_mockMetricRecorder = std::make_shared<NiceMock<metrics::test::MockMetricRecorder>>();
|
||||
m_mockAuthDelegate->setAuthToken(CBL_AUTHORIZATION_TOKEN);
|
||||
HTTP2Transport::Configuration cfg;
|
||||
m_synchronizedMessageRequestQueue = std::make_shared<SynchronizedMessageRequestQueue>();
|
||||
|
||||
m_http2Transport = HTTP2Transport::create(
|
||||
m_mockAuthDelegate,
|
||||
TEST_AVS_GATEWAY_STRING,
|
||||
|
@ -261,7 +274,10 @@ void HTTP2TransportTest::SetUp() {
|
|||
m_mockMessageConsumer,
|
||||
m_attachmentManager,
|
||||
m_mockTransportObserver,
|
||||
m_mockPostConnectFactory);
|
||||
m_mockPostConnectFactory,
|
||||
m_synchronizedMessageRequestQueue,
|
||||
cfg,
|
||||
m_mockMetricRecorder);
|
||||
|
||||
ASSERT_NE(m_http2Transport, nullptr);
|
||||
}
|
||||
|
@ -652,7 +668,8 @@ TEST_F(HTTP2TransportTest, testSlow_messageRequestsQueuing) {
|
|||
auto messageObserver = std::make_shared<TestMessageRequestObserver>();
|
||||
messageObservers.push_back(messageObserver);
|
||||
messageReq->addObserver(messageObserver);
|
||||
m_http2Transport->send(messageReq);
|
||||
m_synchronizedMessageRequestQueue->enqueueRequest(messageReq);
|
||||
m_http2Transport->onRequestEnqueued();
|
||||
}
|
||||
|
||||
// Give m_http2Transport a chance to misbehave and send more than a single request before receiving a response.
|
||||
|
@ -690,6 +707,73 @@ TEST_F(HTTP2TransportTest, testSlow_messageRequestsQueuing) {
|
|||
|
||||
m_http2Transport->shutdown();
|
||||
|
||||
// Count the number of messages that received CANCELED or NOT_CONNECTED event.
|
||||
unsigned messagesCanceled = 0;
|
||||
unsigned messagesRemaining = 0;
|
||||
for (unsigned messageNum = 0; messageNum < messagesCount; messageNum++) {
|
||||
if (messageObservers[messageNum]->m_status.waitFor(RESPONSE_TIMEOUT)) {
|
||||
switch (messageObservers[messageNum]->m_status.getValue()) {
|
||||
case MessageRequestObserverInterface::Status::CANCELED:
|
||||
case MessageRequestObserverInterface::Status::NOT_CONNECTED:
|
||||
messagesCanceled++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (m_synchronizedMessageRequestQueue->dequeueRequest()) {
|
||||
++messagesRemaining;
|
||||
}
|
||||
|
||||
ASSERT_EQ(messagesCanceled + messagesRemaining, messagesCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test MessageRequests are sent for sequential queue types.
|
||||
*/
|
||||
TEST_F(HTTP2TransportTest, messageRequests_SequentialSend) {
|
||||
authorizeAndConnect();
|
||||
|
||||
// Send 5 messages.
|
||||
std::vector<std::shared_ptr<TestMessageRequestObserver>> messageObservers;
|
||||
unsigned int messagesCount = 5; // number of test messages to Send
|
||||
for (unsigned messageNum = 0; messageNum < messagesCount; messageNum++) {
|
||||
std::shared_ptr<MessageRequest> messageReq = std::make_shared<MessageRequest>(TEST_MESSAGE, "");
|
||||
auto messageObserver = std::make_shared<TestMessageRequestObserver>();
|
||||
messageObservers.push_back(messageObserver);
|
||||
messageReq->addObserver(messageObserver);
|
||||
m_synchronizedMessageRequestQueue->enqueueRequest(messageReq);
|
||||
m_http2Transport->onRequestEnqueued();
|
||||
}
|
||||
|
||||
unsigned int postsRequestsCount = 0;
|
||||
while (postsRequestsCount < messagesCount) {
|
||||
// Delayed 200 response for each POST request.
|
||||
std::this_thread::sleep_for(SHORT_DELAY);
|
||||
postsRequestsCount++;
|
||||
|
||||
ASSERT_EQ((int)m_mockHttp2Connection->getPostRequestsNum(), (int)postsRequestsCount);
|
||||
auto request = m_mockHttp2Connection->waitForPostRequest(RESPONSE_TIMEOUT);
|
||||
if (request) {
|
||||
request->getSink()->onReceiveResponseCode(HTTPResponseCode::SUCCESS_OK);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure HTTP2Transport sends out the 5 POST requests.
|
||||
ASSERT_EQ(postsRequestsCount, messagesCount);
|
||||
|
||||
// On disconnect, send CANCELED response for each POST REQUEST.
|
||||
EXPECT_CALL(*m_mockHttp2Connection, disconnect()).WillOnce(Invoke([this]() {
|
||||
while (true) {
|
||||
auto request = m_mockHttp2Connection->dequePostRequest();
|
||||
if (!request) break;
|
||||
|
||||
request->getSink()->onResponseFinished(HTTP2ResponseFinishedStatus::CANCELLED);
|
||||
};
|
||||
}));
|
||||
|
||||
m_http2Transport->shutdown();
|
||||
|
||||
// Count the number of messages that received CANCELED or NOT_CONNECTED event.
|
||||
unsigned messagesCanceled = 0;
|
||||
for (unsigned messageNum = 0; messageNum < messagesCount; messageNum++) {
|
||||
|
@ -792,7 +876,8 @@ TEST_F(HTTP2TransportTest, test_onSendCompletedNotification) {
|
|||
auto messageObserver = std::make_shared<TestMessageRequestObserver>();
|
||||
messageObservers.push_back(messageObserver);
|
||||
messageReq->addObserver(messageObserver);
|
||||
m_http2Transport->send(messageReq);
|
||||
m_synchronizedMessageRequestQueue->enqueueRequest(messageReq);
|
||||
m_http2Transport->onRequestEnqueued();
|
||||
}
|
||||
|
||||
// Send the response code for each POST request.
|
||||
|
@ -836,7 +921,8 @@ TEST_F(HTTP2TransportTest, test_onExceptionReceivedNon200Content) {
|
|||
std::shared_ptr<MessageRequest> messageReq = std::make_shared<MessageRequest>(TEST_MESSAGE, "");
|
||||
auto messageObserver = std::make_shared<TestMessageRequestObserver>();
|
||||
messageReq->addObserver(messageObserver);
|
||||
m_http2Transport->send(messageReq);
|
||||
m_synchronizedMessageRequestQueue->enqueueRequest(messageReq);
|
||||
m_http2Transport->onRequestEnqueued();
|
||||
|
||||
auto request = m_mockHttp2Connection->waitForPostRequest(RESPONSE_TIMEOUT);
|
||||
ASSERT_NE(request, nullptr);
|
||||
|
@ -876,7 +962,8 @@ TEST_F(HTTP2TransportTest, test_messageConsumerReceiveDirective) {
|
|||
std::shared_ptr<MessageRequest> messageReq = std::make_shared<MessageRequest>(TEST_MESSAGE, "");
|
||||
auto messageObserver = std::make_shared<TestMessageRequestObserver>();
|
||||
messageReq->addObserver(messageObserver);
|
||||
m_http2Transport->send(messageReq);
|
||||
m_synchronizedMessageRequestQueue->enqueueRequest(messageReq);
|
||||
m_http2Transport->onRequestEnqueued();
|
||||
|
||||
auto eventStream = m_mockHttp2Connection->waitForPostRequest(RESPONSE_TIMEOUT);
|
||||
ASSERT_NE(eventStream, nullptr);
|
||||
|
@ -904,7 +991,8 @@ TEST_F(HTTP2TransportTest, test_onServerSideDisconnectOnDownchannelClosure) {
|
|||
|
||||
// Send a message.
|
||||
std::shared_ptr<MessageRequest> messageReq = std::make_shared<MessageRequest>(TEST_MESSAGE, "");
|
||||
m_http2Transport->send(messageReq);
|
||||
m_synchronizedMessageRequestQueue->enqueueRequest(messageReq);
|
||||
m_http2Transport->onRequestEnqueued();
|
||||
|
||||
PromiseFuturePair<void> gotOnServerSideDisconnect;
|
||||
auto setGotOnServerSideDisconnect = [&gotOnServerSideDisconnect] { gotOnServerSideDisconnect.setValue(); };
|
||||
|
@ -943,7 +1031,8 @@ TEST_F(HTTP2TransportTest, test_messageRequestTimeoutPingRequest) {
|
|||
|
||||
// Send a message.
|
||||
std::shared_ptr<MessageRequest> messageReq = std::make_shared<MessageRequest>(TEST_MESSAGE, "");
|
||||
m_http2Transport->send(messageReq);
|
||||
m_synchronizedMessageRequestQueue->enqueueRequest(messageReq);
|
||||
m_http2Transport->onRequestEnqueued();
|
||||
|
||||
// Upon receiving the message, the mock HTTP2Connection/request will reply to the request with
|
||||
// onResponseFinished(TIMEOUT).
|
||||
|
@ -978,7 +1067,9 @@ TEST_F(HTTP2TransportTest, testTimer_networkInactivityPingRequest) {
|
|||
m_attachmentManager,
|
||||
m_mockTransportObserver,
|
||||
m_mockPostConnectFactory,
|
||||
cfg);
|
||||
m_synchronizedMessageRequestQueue,
|
||||
cfg,
|
||||
m_mockMetricRecorder);
|
||||
|
||||
authorizeAndConnect();
|
||||
|
||||
|
@ -1023,7 +1114,9 @@ TEST_F(HTTP2TransportTest, testSlow_tearDownPingTimeout) {
|
|||
m_attachmentManager,
|
||||
m_mockTransportObserver,
|
||||
m_mockPostConnectFactory,
|
||||
cfg);
|
||||
m_synchronizedMessageRequestQueue,
|
||||
cfg,
|
||||
m_mockMetricRecorder);
|
||||
|
||||
authorizeAndConnect();
|
||||
|
||||
|
@ -1037,7 +1130,7 @@ TEST_F(HTTP2TransportTest, testSlow_tearDownPingTimeout) {
|
|||
// Reply to a ping request.
|
||||
std::thread pingThread([this]() {
|
||||
auto pingRequest = m_mockHttp2Connection->waitForPingRequest(RESPONSE_TIMEOUT);
|
||||
ASSERT_TRUE(pingRequest);
|
||||
ASSERT_NE(pingRequest, nullptr);
|
||||
m_mockHttp2Connection->dequePingRequest();
|
||||
pingRequest->getSink()->onResponseFinished(HTTP2ResponseFinishedStatus::TIMEOUT);
|
||||
});
|
||||
|
@ -1065,7 +1158,9 @@ TEST_F(HTTP2TransportTest, testSlow_tearDownPingFailure) {
|
|||
m_attachmentManager,
|
||||
m_mockTransportObserver,
|
||||
m_mockPostConnectFactory,
|
||||
cfg);
|
||||
m_synchronizedMessageRequestQueue,
|
||||
cfg,
|
||||
m_mockMetricRecorder);
|
||||
|
||||
authorizeAndConnect();
|
||||
|
||||
|
@ -1079,7 +1174,7 @@ TEST_F(HTTP2TransportTest, testSlow_tearDownPingFailure) {
|
|||
// Reply to a ping request.
|
||||
std::thread pingThread([this]() {
|
||||
auto pingRequest = m_mockHttp2Connection->waitForPingRequest(RESPONSE_TIMEOUT);
|
||||
ASSERT_TRUE(pingRequest);
|
||||
ASSERT_NE(pingRequest, nullptr);
|
||||
m_mockHttp2Connection->dequePingRequest();
|
||||
pingRequest->getSink()->onReceiveResponseCode(HTTPResponseCode::CLIENT_ERROR_BAD_REQUEST);
|
||||
pingRequest->getSink()->onResponseFinished(HTTP2ResponseFinishedStatus::COMPLETE);
|
||||
|
@ -1112,11 +1207,12 @@ TEST_F(HTTP2TransportTest, testSlow_avsStreamsLimit) {
|
|||
auto messageObserver = std::make_shared<TestMessageRequestObserver>();
|
||||
messageObservers.push_back(messageObserver);
|
||||
messageReq->addObserver(messageObserver);
|
||||
m_http2Transport->send(messageReq);
|
||||
m_synchronizedMessageRequestQueue->enqueueRequest(messageReq);
|
||||
m_http2Transport->onRequestEnqueued();
|
||||
}
|
||||
|
||||
// Check that there was a downchannel request sent out.
|
||||
ASSERT_TRUE(m_mockHttp2Connection->getDownchannelRequest(RESPONSE_TIMEOUT));
|
||||
ASSERT_NE(m_mockHttp2Connection->getDownchannelRequest(RESPONSE_TIMEOUT), nullptr);
|
||||
|
||||
// Check the messages we sent were limited.
|
||||
ASSERT_EQ(m_mockHttp2Connection->getPostRequestsNum(), MAX_POST_STREAMS);
|
||||
|
|
|
@ -105,7 +105,7 @@ TEST_F(MessageRouterTest, test_sendIsSuccessfulWhenConnected) {
|
|||
auto messageRequest = createMessageRequest();
|
||||
|
||||
// Expect to have the message sent to the transport
|
||||
EXPECT_CALL(*m_mockTransport, send(messageRequest)).Times(1);
|
||||
EXPECT_CALL(*m_mockTransport, onRequestEnqueued()).Times(1);
|
||||
|
||||
m_router->sendMessage(messageRequest);
|
||||
|
||||
|
@ -116,8 +116,8 @@ TEST_F(MessageRouterTest, test_sendIsSuccessfulWhenConnected) {
|
|||
TEST_F(MessageRouterTest, test_sendFailsWhenDisconnected) {
|
||||
auto messageRequest = createMessageRequest();
|
||||
|
||||
// Expect to have the message sent to the transport
|
||||
EXPECT_CALL(*m_mockTransport, send(messageRequest)).Times(0);
|
||||
// Expect to have the message to be enqueued but the transport is not notified
|
||||
EXPECT_CALL(*m_mockTransport, onRequestEnqueued()).Times(0);
|
||||
|
||||
m_router->sendMessage(messageRequest);
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ TEST_F(MessageRouterTest, test_sendFailsWhenPending) {
|
|||
auto messageRequest = createMessageRequest();
|
||||
|
||||
// Expect to have the message sent to the transport.
|
||||
EXPECT_CALL(*m_mockTransport, send(messageRequest)).Times(1);
|
||||
EXPECT_CALL(*m_mockTransport, onRequestEnqueued()).Times(1);
|
||||
|
||||
m_router->sendMessage(messageRequest);
|
||||
waitOnMessageRouter(SHORT_TIMEOUT_MS);
|
||||
|
@ -145,7 +145,7 @@ TEST_F(MessageRouterTest, test_sendMessageDoesNotSendAfterDisconnected) {
|
|||
m_router->disable();
|
||||
|
||||
// Expect to have the message sent to the transport
|
||||
EXPECT_CALL(*m_mockTransport, send(messageRequest)).Times(0);
|
||||
EXPECT_CALL(*m_mockTransport, onRequestEnqueued()).Times(0);
|
||||
|
||||
m_router->sendMessage(messageRequest);
|
||||
}
|
||||
|
@ -202,9 +202,9 @@ TEST_F(MessageRouterTest, test_serverSideDisconnectCreatesANewTransport) {
|
|||
|
||||
auto messageRequest = createMessageRequest();
|
||||
|
||||
EXPECT_CALL(*oldTransport.get(), send(messageRequest)).Times(0);
|
||||
EXPECT_CALL(*oldTransport.get(), onRequestEnqueued()).Times(0);
|
||||
|
||||
EXPECT_CALL(*newTransport.get(), send(messageRequest)).Times(1);
|
||||
EXPECT_CALL(*newTransport.get(), onRequestEnqueued()).Times(1);
|
||||
|
||||
m_router->sendMessage(messageRequest);
|
||||
|
||||
|
|
|
@ -80,7 +80,8 @@ private:
|
|||
std::shared_ptr<AttachmentManager> attachmentManager,
|
||||
const std::string& avsGateway,
|
||||
std::shared_ptr<MessageConsumerInterface> messageConsumerInterface,
|
||||
std::shared_ptr<TransportObserverInterface> transportObserverInterface) override {
|
||||
std::shared_ptr<TransportObserverInterface> transportObserverInterface,
|
||||
std::shared_ptr<SynchronizedMessageRequestQueue> sharedMessageRequestQueue) override {
|
||||
return m_mockTransport;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -22,6 +22,7 @@
|
|||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
@ -57,6 +58,8 @@ public:
|
|||
/// @{
|
||||
std::shared_ptr<HTTP2RequestInterface> createAndSendRequest(const HTTP2RequestConfig& config);
|
||||
MOCK_METHOD0(disconnect, void());
|
||||
void addObserver(std::shared_ptr<avsCommon::utils::http2::HTTP2ConnectionObserverInterface> observer);
|
||||
void removeObserver(std::shared_ptr<avsCommon::utils::http2::HTTP2ConnectionObserverInterface> observer);
|
||||
/// @}
|
||||
|
||||
/**
|
||||
|
@ -237,6 +240,12 @@ private:
|
|||
/// Queue of Ping requests. Serialized by @c m_pingRequestMutex.
|
||||
std::deque<std::shared_ptr<MockHTTP2Request>> m_pingRequestQueue;
|
||||
|
||||
/// Mutex for observers.
|
||||
std::mutex m_observersMutex;
|
||||
|
||||
/// Observers
|
||||
std::unordered_set<std::shared_ptr<avsCommon::utils::http2::HTTP2ConnectionObserverInterface>> m_observers;
|
||||
|
||||
/// Serializes access to receiving Ping requests.
|
||||
std::mutex m_pingRequestMutex;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -40,7 +40,8 @@ public:
|
|||
MOCK_METHOD0(disconnect, void());
|
||||
MOCK_METHOD0(isConnected, bool());
|
||||
MOCK_METHOD0(isPendingDisconnected, bool());
|
||||
MOCK_METHOD1(send, void(std::shared_ptr<avsCommon::avs::MessageRequest>));
|
||||
MOCK_METHOD0(onRequestEnqueued, void());
|
||||
MOCK_METHOD1(sendPostConnectMessage, void(std::shared_ptr<avsCommon::avs::MessageRequest>));
|
||||
MOCK_METHOD2(onAttachmentReceived, void(const std::string& contextId, const std::string& message));
|
||||
|
||||
const int m_id;
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <AVSCommon/AVS/DirectiveHandlerConfiguration.h>
|
||||
#include <AVSCommon/AVS/HandlerAndPolicy.h>
|
||||
#include <AVSCommon/Utils/RequiresShutdown.h>
|
||||
#include <AVSCommon/Utils/Metrics/MetricEventBuilder.h>
|
||||
#include <AVSCommon/Utils/Metrics/MetricRecorderInterface.h>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace adsl {
|
||||
|
@ -34,7 +36,8 @@ namespace adsl {
|
|||
class DirectiveRouter : public avsCommon::utils::RequiresShutdown {
|
||||
public:
|
||||
/// Constructor.
|
||||
DirectiveRouter();
|
||||
/// @param metricRecorder The metric recorder.
|
||||
DirectiveRouter(std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder = nullptr);
|
||||
|
||||
/**
|
||||
* Add mappings from handler's directives to @c BlockingPolicy values, gotten through the
|
||||
|
@ -194,6 +197,9 @@ private:
|
|||
*/
|
||||
bool removeDirectiveHandlerLocked(std::shared_ptr<avsCommon::sdkInterfaces::DirectiveHandlerInterface> handler);
|
||||
|
||||
/// The metric recorder.
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> m_metricRecorder;
|
||||
|
||||
/// A mutex used to serialize access to @c m_configuration and @c m_handlerReferenceCounts.
|
||||
std::mutex m_mutex;
|
||||
|
||||
|
@ -211,6 +217,16 @@ private:
|
|||
*/
|
||||
std::unordered_map<std::shared_ptr<avsCommon::sdkInterfaces::DirectiveHandlerInterface>, int>
|
||||
m_handlerReferenceCounts;
|
||||
|
||||
/**
|
||||
* Submit metrics related to the given directive.
|
||||
*
|
||||
* @param metricEventBuilder The metric event builder to be used.
|
||||
* @param directive The given directive.
|
||||
*/
|
||||
void submitMetric(
|
||||
avsCommon::utils::metrics::MetricEventBuilder& metricEventBuilder,
|
||||
const std::shared_ptr<avsCommon::avs::AVSDirective>& directive);
|
||||
};
|
||||
|
||||
} // namespace adsl
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <AVSCommon/SDKInterfaces/ExceptionEncounteredSenderInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/DirectiveSequencerInterface.h>
|
||||
#include <AVSCommon/Utils/Metrics/MetricRecorderInterface.h>
|
||||
|
||||
#include "ADSL/DirectiveProcessor.h"
|
||||
#include "ADSL/DirectiveRouter.h"
|
||||
|
@ -41,10 +42,12 @@ public:
|
|||
*
|
||||
* @param exceptionSender An instance of the @c ExceptionEncounteredSenderInterface used to send
|
||||
* ExceptionEncountered messages to AVS for directives that are not handled.
|
||||
* @param metricRecorder The metric recorder.
|
||||
* @return Returns a new DirectiveSequencer, or nullptr if the operation failed.
|
||||
*/
|
||||
static std::unique_ptr<DirectiveSequencerInterface> create(
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> exceptionSender);
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> exceptionSender,
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder = nullptr);
|
||||
|
||||
bool addDirectiveHandler(std::shared_ptr<avsCommon::sdkInterfaces::DirectiveHandlerInterface> handler) override;
|
||||
|
||||
|
@ -63,11 +66,13 @@ public:
|
|||
private:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param exceptionSender An instance of the @c ExceptionEncounteredSenderInterface used to send
|
||||
* ExceptionEncountered messages to AVS for directives that are not handled.
|
||||
* @param metricRecorder The metric recorder.
|
||||
*/
|
||||
DirectiveSequencer(std::shared_ptr<avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> exceptionSender);
|
||||
DirectiveSequencer(
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> exceptionSender,
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder);
|
||||
|
||||
void doShutdown() override;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -21,6 +21,7 @@
|
|||
#include <AVSCommon/SDKInterfaces/ExceptionEncounteredSenderInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/DirectiveSequencerInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/MessageObserverInterface.h>
|
||||
#include <AVSCommon/Utils/Metrics/MetricRecorderInterface.h>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace adsl {
|
||||
|
@ -39,11 +40,13 @@ public:
|
|||
* @param directiveSequencerInterface The DirectiveSequencerInterface implementation, which will receive
|
||||
* @c AVSDirectives.
|
||||
* @param attachmentManager The @c AttachmentManager which created @c AVSDirectives will use to acquire Attachments.
|
||||
* @param metricRecorder The metric recorder.
|
||||
*/
|
||||
MessageInterpreter(
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> exceptionEncounteredSender,
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::DirectiveSequencerInterface> directiveSequencer,
|
||||
std::shared_ptr<avsCommon::avs::attachment::AttachmentManagerInterface> attachmentManager);
|
||||
std::shared_ptr<avsCommon::avs::attachment::AttachmentManagerInterface> attachmentManager,
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder = nullptr);
|
||||
|
||||
void receive(const std::string& contextId, const std::string& message) override;
|
||||
|
||||
|
@ -52,8 +55,10 @@ private:
|
|||
std::shared_ptr<avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> m_exceptionEncounteredSender;
|
||||
/// Object to which we will send @c AVSDirectives.
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::DirectiveSequencerInterface> m_directiveSequencer;
|
||||
// The attachment manager.
|
||||
/// The attachment manager.
|
||||
std::shared_ptr<avsCommon::avs::attachment::AttachmentManagerInterface> m_attachmentManager;
|
||||
/// The metric recorder.
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> m_metricRecorder;
|
||||
};
|
||||
|
||||
} // namespace adsl
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
#include <vector>
|
||||
|
||||
#include <AVSCommon/AVS/DirectiveRoutingRule.h>
|
||||
#include <AVSCommon/AVS/NamespaceAndName.h>
|
||||
#include <AVSCommon/Utils/Logger/Logger.h>
|
||||
#include <AVSCommon/Utils/Metrics/DataPointCounterBuilder.h>
|
||||
#include <AVSCommon/Utils/Metrics/DataPointStringBuilder.h>
|
||||
#include <AVSCommon/Utils/Optional.h>
|
||||
|
||||
#include "ADSL/DirectiveRouter.h"
|
||||
|
@ -42,8 +43,40 @@ using namespace avsCommon::avs;
|
|||
using namespace avsCommon::avs::directiveRoutingRule;
|
||||
using namespace avsCommon::sdkInterfaces;
|
||||
using namespace avsCommon::utils;
|
||||
using namespace avsCommon::utils::metrics;
|
||||
|
||||
DirectiveRouter::DirectiveRouter() : RequiresShutdown{"DirectiveRouter"} {
|
||||
/// Prefix used in metrics published in this module.
|
||||
static const std::string DIRECTIVE_SEQUENCER_METRIC_PREFIX = "DIRECTIVE_SEQUENCER-";
|
||||
|
||||
/// Metric name for directives that were dispatched immediately.
|
||||
static const std::string DIRECTIVE_DISPATCHED_IMMEDIATE = "DIRECTIVE_DISPATCHED_IMMEDIATE";
|
||||
|
||||
/// Metric name for directives that were pre-handled.
|
||||
static const std::string DIRECTIVE_DISPATCHED_PRE_HANDLE = "DIRECTIVE_DISPATCHED_PRE_HANDLE";
|
||||
|
||||
/// Metric name for directives that were handled directly.
|
||||
static const std::string DIRECTIVE_DISPATCHED_HANDLE = "DIRECTIVE_DISPATCHED_HANDLE";
|
||||
|
||||
void DirectiveRouter::submitMetric(
|
||||
MetricEventBuilder& metricEventBuilder,
|
||||
const std::shared_ptr<AVSDirective>& directive) {
|
||||
if (directive) {
|
||||
metricEventBuilder.addDataPoint(
|
||||
DataPointStringBuilder{}.setName("HTTP2_STREAM").setValue(directive->getAttachmentContextId()).build());
|
||||
metricEventBuilder.addDataPoint(
|
||||
DataPointStringBuilder{}.setName("DIRECTIVE_MESSAGE_ID").setValue(directive->getMessageId()).build());
|
||||
}
|
||||
auto metricEvent = metricEventBuilder.build();
|
||||
if (metricEvent) {
|
||||
recordMetric(m_metricRecorder, metricEvent);
|
||||
} else {
|
||||
ACSDK_ERROR(LX("submitMetricFailed").d("reason", "buildMetricFailed"));
|
||||
}
|
||||
}
|
||||
|
||||
DirectiveRouter::DirectiveRouter(std::shared_ptr<MetricRecorderInterface> metricRecorder) :
|
||||
RequiresShutdown{"DirectiveRouter"},
|
||||
m_metricRecorder{metricRecorder} {
|
||||
}
|
||||
|
||||
bool DirectiveRouter::addDirectiveHandler(std::shared_ptr<DirectiveHandlerInterface> handler) {
|
||||
|
@ -161,6 +194,13 @@ bool DirectiveRouter::handleDirectiveImmediately(std::shared_ptr<avsCommon::avs:
|
|||
}
|
||||
ACSDK_INFO(LX("handleDirectiveImmediately").d("messageId", directive->getMessageId()).d("action", "calling"));
|
||||
HandlerCallScope scope(lock, this, handlerAndPolicy.handler);
|
||||
|
||||
submitMetric(
|
||||
MetricEventBuilder{}
|
||||
.setActivityName(DIRECTIVE_SEQUENCER_METRIC_PREFIX + DIRECTIVE_DISPATCHED_IMMEDIATE)
|
||||
.addDataPoint(DataPointCounterBuilder{}.setName(DIRECTIVE_DISPATCHED_IMMEDIATE).increment(1).build()),
|
||||
directive);
|
||||
|
||||
handlerAndPolicy.handler->handleDirectiveImmediately(directive);
|
||||
return true;
|
||||
}
|
||||
|
@ -178,6 +218,13 @@ bool DirectiveRouter::preHandleDirective(
|
|||
}
|
||||
ACSDK_INFO(LX("preHandleDirective").d("messageId", directive->getMessageId()).d("action", "calling"));
|
||||
HandlerCallScope scope(lock, this, handler);
|
||||
|
||||
submitMetric(
|
||||
MetricEventBuilder{}
|
||||
.setActivityName(DIRECTIVE_SEQUENCER_METRIC_PREFIX + DIRECTIVE_DISPATCHED_PRE_HANDLE)
|
||||
.addDataPoint(DataPointCounterBuilder{}.setName(DIRECTIVE_DISPATCHED_PRE_HANDLE).increment(1).build()),
|
||||
directive);
|
||||
|
||||
handler->preHandleDirective(directive, std::move(result));
|
||||
return true;
|
||||
}
|
||||
|
@ -192,6 +239,13 @@ bool DirectiveRouter::handleDirective(const std::shared_ptr<AVSDirective>& direc
|
|||
}
|
||||
ACSDK_INFO(LX("handleDirective").d("messageId", directive->getMessageId()).d("action", "calling"));
|
||||
HandlerCallScope scope(lock, this, handler);
|
||||
|
||||
submitMetric(
|
||||
MetricEventBuilder{}
|
||||
.setActivityName(DIRECTIVE_SEQUENCER_METRIC_PREFIX + DIRECTIVE_DISPATCHED_HANDLE)
|
||||
.addDataPoint(DataPointCounterBuilder{}.setName(DIRECTIVE_DISPATCHED_HANDLE).increment(1).build()),
|
||||
directive);
|
||||
|
||||
auto result = handler->handleDirective(directive->getMessageId());
|
||||
if (!result) {
|
||||
ACSDK_WARN(LX("messageIdNotRecognized")
|
||||
|
|
|
@ -42,12 +42,13 @@ using namespace avsCommon::sdkInterfaces;
|
|||
using namespace avsCommon::utils;
|
||||
|
||||
std::unique_ptr<DirectiveSequencerInterface> DirectiveSequencer::create(
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> exceptionSender) {
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> exceptionSender,
|
||||
std::shared_ptr<metrics::MetricRecorderInterface> metricRecorder) {
|
||||
if (!exceptionSender) {
|
||||
ACSDK_INFO(LX("createFailed").d("reason", "nullptrExceptionSender"));
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<DirectiveSequencerInterface>(new DirectiveSequencer(exceptionSender));
|
||||
return std::unique_ptr<DirectiveSequencerInterface>(new DirectiveSequencer(exceptionSender, metricRecorder));
|
||||
}
|
||||
|
||||
bool DirectiveSequencer::addDirectiveHandler(std::shared_ptr<DirectiveHandlerInterface> handler) {
|
||||
|
@ -86,12 +87,14 @@ bool DirectiveSequencer::onDirective(std::shared_ptr<AVSDirective> directive) {
|
|||
}
|
||||
|
||||
DirectiveSequencer::DirectiveSequencer(
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> exceptionSender) :
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> exceptionSender,
|
||||
std::shared_ptr<metrics::MetricRecorderInterface> metricRecorder) :
|
||||
DirectiveSequencerInterface{"DirectiveSequencer"},
|
||||
m_mutex{},
|
||||
m_exceptionSender{exceptionSender},
|
||||
m_isShuttingDown{false},
|
||||
m_isEnabled{true} {
|
||||
m_isEnabled{true},
|
||||
m_directiveRouter{metricRecorder} {
|
||||
m_directiveProcessor = std::make_shared<DirectiveProcessor>(&m_directiveRouter);
|
||||
m_receivingThread = std::thread(&DirectiveSequencer::receivingLoop, this);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -15,6 +15,9 @@
|
|||
|
||||
#include "ADSL/MessageInterpreter.h"
|
||||
|
||||
#include <AVSCommon/Utils/Metrics/DataPointCounterBuilder.h>
|
||||
#include <AVSCommon/Utils/Metrics/DataPointStringBuilder.h>
|
||||
#include <AVSCommon/Utils/Metrics/MetricEventBuilder.h>
|
||||
#include <AVSCommon/Utils/Metrics.h>
|
||||
|
||||
#include <AVSCommon/Utils/Logger/Logger.h>
|
||||
|
@ -27,6 +30,13 @@ using namespace avsCommon::avs;
|
|||
using namespace avsCommon::avs::attachment;
|
||||
using namespace avsCommon::sdkInterfaces;
|
||||
using namespace avsCommon::utils;
|
||||
using namespace avsCommon::utils::metrics;
|
||||
|
||||
/// Metric recorded when parse has been completed.
|
||||
static const std::string PARSE_COMPLETE("PARSE_COMPLETE");
|
||||
|
||||
/// The metric activity name for parsing completed.
|
||||
static const std::string PARSE_COMPLETE_ACTIVITY_NAME("MESSAGE_INTERPRETER-" + PARSE_COMPLETE);
|
||||
|
||||
/// String to identify log entries originating from this file.
|
||||
static const std::string TAG("MessageInterpreter");
|
||||
|
@ -41,10 +51,12 @@ static const std::string TAG("MessageInterpreter");
|
|||
MessageInterpreter::MessageInterpreter(
|
||||
std::shared_ptr<ExceptionEncounteredSenderInterface> exceptionEncounteredSender,
|
||||
std::shared_ptr<DirectiveSequencerInterface> directiveSequencer,
|
||||
std::shared_ptr<AttachmentManagerInterface> attachmentManager) :
|
||||
std::shared_ptr<AttachmentManagerInterface> attachmentManager,
|
||||
std::shared_ptr<MetricRecorderInterface> metricRecorder) :
|
||||
m_exceptionEncounteredSender{exceptionEncounteredSender},
|
||||
m_directiveSequencer{directiveSequencer},
|
||||
m_attachmentManager{attachmentManager} {
|
||||
m_attachmentManager{attachmentManager},
|
||||
m_metricRecorder{metricRecorder} {
|
||||
}
|
||||
|
||||
void MessageInterpreter::receive(const std::string& contextId, const std::string& message) {
|
||||
|
@ -64,6 +76,24 @@ void MessageInterpreter::receive(const std::string& contextId, const std::string
|
|||
return;
|
||||
}
|
||||
|
||||
auto metricEvent =
|
||||
MetricEventBuilder{}
|
||||
.setActivityName(PARSE_COMPLETE_ACTIVITY_NAME)
|
||||
.addDataPoint(DataPointCounterBuilder{}.setName(PARSE_COMPLETE).increment(1).build())
|
||||
.addDataPoint(DataPointStringBuilder{}
|
||||
.setName("HTTP2_STREAM")
|
||||
.setValue(avsDirective->getAttachmentContextId())
|
||||
.build())
|
||||
.addDataPoint(
|
||||
DataPointStringBuilder{}.setName("DIRECTIVE_MESSAGE_ID").setValue(avsDirective->getMessageId()).build())
|
||||
.build();
|
||||
|
||||
if (metricEvent == nullptr) {
|
||||
ACSDK_ERROR(LX("Error creating metric."));
|
||||
return;
|
||||
}
|
||||
recordMetric(m_metricRecorder, metricEvent);
|
||||
|
||||
if (avsDirective->getName() == "StopCapture" || avsDirective->getName() == "Speak") {
|
||||
ACSDK_METRIC_MSG(TAG, avsDirective, Metrics::Location::ADSL_ENQUEUE);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <gmock/gmock.h>
|
||||
|
||||
#include <AVSCommon/AVS/Attachment/AttachmentManager.h>
|
||||
#include <AVSCommon/AVS/NamespaceAndName.h>
|
||||
#include <AVSCommon/SDKInterfaces/MockDirectiveHandlerResult.h>
|
||||
|
||||
#include "ADSL/DirectiveRouter.h"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -16,25 +16,33 @@
|
|||
#ifndef ALEXA_CLIENT_SDK_AFML_INCLUDE_AFML_CHANNEL_H_
|
||||
#define ALEXA_CLIENT_SDK_AFML_INCLUDE_AFML_CHANNEL_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <AVSCommon/SDKInterfaces/ChannelObserverInterface.h>
|
||||
#include <AVSCommon/AVS/ContentType.h>
|
||||
#include <AVSCommon/AVS/FocusState.h>
|
||||
#include <AVSCommon/SDKInterfaces/ChannelObserverInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/FocusManagerInterface.h>
|
||||
#include <AVSCommon/Utils/Timing/Timer.h>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace afml {
|
||||
|
||||
/**
|
||||
* A Channel represents a focusable layer with a priority, allowing the observer which has acquired the Channel to
|
||||
* understand focus changes.
|
||||
* understand focus changes. A Channel can be acquired by multiple Activities, but only a single Activity can be
|
||||
* the primary activity. All other Activities that are not the primary Activity will be backgrounded.
|
||||
*
|
||||
* A Channel can optionally be virtual. Activity changes will not be captured for virtual
|
||||
* channels.
|
||||
*/
|
||||
class Channel {
|
||||
public:
|
||||
/*
|
||||
* This class contains the states of the @c Channel. The states inside this structure are intended to be shared via
|
||||
* the @c ActivityTrackerInterface.
|
||||
* This class contains the states of the @c Channel.
|
||||
*/
|
||||
struct State {
|
||||
/// Constructor with @c Channel name as the parameter.
|
||||
|
@ -64,8 +72,11 @@ public:
|
|||
*
|
||||
* @param name The channel's name.
|
||||
* @param priority The priority of the channel.
|
||||
* @param isVirtual bool to indicate if this channel is a virtual channel.
|
||||
*
|
||||
* @note refer to the class level doc on virtual channel paramter.
|
||||
*/
|
||||
Channel(const std::string& name, const unsigned int priority);
|
||||
Channel(const std::string& name, const unsigned int priority, bool isVirtual = false);
|
||||
|
||||
/**
|
||||
* Returns the name of a channel.
|
||||
|
@ -82,28 +93,52 @@ public:
|
|||
unsigned int getPriority() const;
|
||||
|
||||
/**
|
||||
* Updates the focus and notifies the Channel's observer, if there is one, of the focus change. This method does
|
||||
* not return until the ChannelObserverInterface##onFocusChanged() callback to the observer returns. If the focus
|
||||
* @c NONE, the observer will be removed from the Channel.
|
||||
* Updates the focus and notifies all activities associated with the @c Channel of the focus change. If @c
|
||||
* FocusState is FOREGROUND, then the most recent Activity added to the Channel will be moved to foreground state,
|
||||
* and all other Activites will remain in background state. This method does not return until the
|
||||
* ChannelObserverInterface##onFocusChanged() callbacks to all the associated activities return. If the focus is @c
|
||||
* NONE, the Activity will be removed from the Channel.
|
||||
*
|
||||
* @note the @c MixingBehavior should pertain to the primary Activity for the Channel.
|
||||
*
|
||||
* @param focus The focus of the Channel.
|
||||
* @param behavior The MixingBehavior of the Channel.
|
||||
* @param forceUpdate bool to indicate if the operation must be forced (irrespective of focus/behavior change).
|
||||
* @return @c true if focus changed, else @c false.
|
||||
*/
|
||||
bool setFocus(avsCommon::avs::FocusState focus);
|
||||
bool setFocus(avsCommon::avs::FocusState focus, avsCommon::avs::MixingBehavior behavior, bool forceUpdate = false);
|
||||
|
||||
/**
|
||||
* Sets a new observer.
|
||||
* Set the Primary Activity on the @c Channel given the Activity Object. The function must be called after the
|
||||
* correct FocusState of the Channel is set. Any other Activities on the Channel will be moved to the background
|
||||
* state.
|
||||
*
|
||||
* @param observer The observer of the Channel.
|
||||
* @param activity @c Activity to be set as Primary Activity.
|
||||
*/
|
||||
void setObserver(std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface> observer);
|
||||
void setPrimaryActivity(std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> activity);
|
||||
|
||||
/**
|
||||
* Checks whether the Channel has an observer.
|
||||
* Activity to be released by observer.
|
||||
*
|
||||
* @return @c true if the Channel has an observer, else @c false.
|
||||
* @param observer Channel Observer to release.
|
||||
* @return @c true if Activity was found and released, @c false otherwise.
|
||||
*/
|
||||
bool hasObserver() const;
|
||||
bool releaseActivity(std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface> observer);
|
||||
|
||||
/**
|
||||
* Activity to be released by interface.
|
||||
*
|
||||
* @param interfaceName The interface name of the Activity to release.
|
||||
*/
|
||||
bool releaseActivity(const std::string& interfaceName);
|
||||
|
||||
/**
|
||||
* Returns if channel is active.
|
||||
* A Channel is considered active if there is any Activity on the Channel.
|
||||
*
|
||||
* @return @c true if Channel is active, @c false otherwise.
|
||||
*/
|
||||
bool isActive();
|
||||
|
||||
/**
|
||||
* Compares this Channel and another Channel and checks which is higher priority. A Channel is considered higher
|
||||
|
@ -114,27 +149,12 @@ public:
|
|||
bool operator>(const Channel& rhs) const;
|
||||
|
||||
/**
|
||||
* Updates the AVS interface occupying the Channel.
|
||||
*
|
||||
* @param interface The name of the interface occupying the Channel.
|
||||
*/
|
||||
void setInterface(const std::string& interface);
|
||||
|
||||
/**
|
||||
* Returns the name of the AVS interface occupying the Channel.
|
||||
* Returns the name of the interface of the Primary Activity occupying the Channel.
|
||||
*
|
||||
* @return The name of the AVS interface.
|
||||
*/
|
||||
std::string getInterface() const;
|
||||
|
||||
/**
|
||||
* Checks whether the observer passed in currently owns the Channel.
|
||||
*
|
||||
* @param observer The observer to check.
|
||||
* @return @c true if the observer currently owns the Channel and @c false otherwise.
|
||||
*/
|
||||
bool doesObserverOwnChannel(std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface> observer) const;
|
||||
|
||||
/**
|
||||
* Returns the @c State of the @c Channel.
|
||||
*
|
||||
|
@ -142,17 +162,131 @@ public:
|
|||
*/
|
||||
Channel::State getState() const;
|
||||
|
||||
/**
|
||||
* Returns a list of Channel::State updates. This API will internally clear
|
||||
* the stored updates when called.
|
||||
*
|
||||
* @return vector containing all Channel::State Updates
|
||||
*/
|
||||
std::vector<Channel::State> getActivityUpdates();
|
||||
|
||||
/**
|
||||
* Returns the primary activity associated with this channel
|
||||
*
|
||||
* @return the primary activity associated with the channel.
|
||||
*/
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> getPrimaryActivity();
|
||||
|
||||
/**
|
||||
* Gets the activity associated with a given interfaceName.
|
||||
*
|
||||
* @param interfaceName interface name associated with the activity being searched
|
||||
* @return activity associated with @param interfaceName, nullptr if not found.
|
||||
*/
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> getActivity(
|
||||
const std::string& interfaceName);
|
||||
|
||||
/**
|
||||
* Retrieve vector of interfaces of all Activites on the Channel.
|
||||
*/
|
||||
std::vector<std::string> getInterfaceList() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Notify all the Activities associated with the @c Channel. All activities that are not
|
||||
* the primary activity, will be passed MixingBehavior::MUST_PAUSE. The primary activity shall
|
||||
* receive the behavior passed as input to the API.
|
||||
*
|
||||
* @param behavior MixingBehavior to notify the activities with.
|
||||
* @param focusState FocusState to notify the activities with.
|
||||
*/
|
||||
void notifyActivities(avsCommon::avs::MixingBehavior behavior, avsCommon::avs::FocusState focusState);
|
||||
|
||||
/**
|
||||
* Activity to be released.
|
||||
*
|
||||
* @param activityToRelease The Activity to be released from the Channel.
|
||||
* @return bool true if the operation was successful, otherwise false.
|
||||
*/
|
||||
bool releaseActivityLocked(
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> activityToRelease);
|
||||
|
||||
/**
|
||||
* Helper to remove Activity from the list, also update Channel::State updates as required.
|
||||
*
|
||||
* @param activity Activity Iterator to remove.
|
||||
* @return The @c true if successful and @c false otherwise.
|
||||
*/
|
||||
bool removeActivityHelperLocked(
|
||||
std::list<std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity>>::iterator
|
||||
activityToRemoveIt);
|
||||
/**
|
||||
* Adds a Channel State entry to Channel::State updates with current m_state with a specified
|
||||
* focusState and interface name.
|
||||
*
|
||||
* @param interfaceName Interface Name to add to the Channel::State updates.
|
||||
* @param focusState FocusState to add to the Channel::State updates.
|
||||
*/
|
||||
void addToChannelUpdatesLocked(const std::string& interfaceName, avsCommon::avs::FocusState focusState);
|
||||
|
||||
/**
|
||||
* Given incoming and current activity, process the policies to either release, not release,
|
||||
* or start patience timer for the current Activity.
|
||||
*
|
||||
* @param incomingActivity incoming Activity.
|
||||
* @param currentActivity current Activity.
|
||||
*/
|
||||
void processPolicyLocked(
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> incomingActivity,
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> currentActivity);
|
||||
|
||||
/**
|
||||
* Patience Timer Callback. Function is to be executed when patience timer expires.
|
||||
*
|
||||
* @param activity activity to release after timer is expired.
|
||||
*/
|
||||
void patienceTimerCallback(std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> activity);
|
||||
|
||||
/**
|
||||
* Update Channel Interface with the Activity at top of stack.
|
||||
*/
|
||||
void updateChannelInterfaceLocked();
|
||||
|
||||
/**
|
||||
* Returns the primary activity associated with this channel in a locked context.
|
||||
*
|
||||
* @return the primary activity associated with the channel.
|
||||
*/
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> getPrimaryActivityLocked() const;
|
||||
|
||||
private:
|
||||
/// The priority of the Channel.
|
||||
const unsigned int m_priority;
|
||||
|
||||
/// Flag to indicate if this is a virtual channel
|
||||
bool m_isVirtual;
|
||||
|
||||
/// The @c State of the @c Channel.
|
||||
State m_state;
|
||||
|
||||
/// The current observer of the Channel.
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface> m_observer;
|
||||
};
|
||||
/// The list to hold shared pointer to all Activities.
|
||||
std::list<std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity>> m_activities;
|
||||
|
||||
/// Mutex to protect m_state and m_activities.
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
/// The vector to hold activity updates for the Channel.
|
||||
std::vector<Channel::State> m_activityUpdates;
|
||||
|
||||
/// A timer task to trace the patience.
|
||||
avsCommon::utils::timing::Timer m_patienceTimer;
|
||||
|
||||
/// Activity to track the initiator of patience.
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> m_patienceInitiator;
|
||||
|
||||
/// Activity to track the receiver of patience.
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> m_patienceReceiver;
|
||||
};
|
||||
} // namespace afml
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +16,7 @@
|
|||
#ifndef ALEXA_CLIENT_SDK_AFML_INCLUDE_AFML_FOCUSMANAGER_H_
|
||||
#define ALEXA_CLIENT_SDK_AFML_INCLUDE_AFML_FOCUSMANAGER_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
@ -29,6 +30,7 @@
|
|||
#include "AFML/Channel.h"
|
||||
#include "AFML/ActivityTrackerInterface.h"
|
||||
#include "AVSCommon/Utils/Threading/Executor.h"
|
||||
#include "InterruptModel/InterruptModel.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace afml {
|
||||
|
@ -56,7 +58,8 @@ public:
|
|||
* The configuration used by the FocusManager to create Channel objects. Each configuration object has a
|
||||
* name and priority.
|
||||
*/
|
||||
struct ChannelConfiguration {
|
||||
class ChannelConfiguration {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
|
@ -83,6 +86,18 @@ public:
|
|||
|
||||
/// The priority of the channel.
|
||||
unsigned int priority;
|
||||
|
||||
/**
|
||||
* Get the virtual channel configurations.
|
||||
*
|
||||
* @param channelTypeKey The key of the virtual channel configuration to get.
|
||||
* @param[out] virtualChannelConfiguration The @c ChannelConfiguration for the virtual channels as specified in
|
||||
* @c channelTypeKey. An empty vector if there is no such info on the configuration file.
|
||||
* @return true if there's no error, false otherwise.
|
||||
*/
|
||||
static bool readChannelConfiguration(
|
||||
const std::string& channelTypeKey,
|
||||
std::vector<afml::FocusManager::ChannelConfiguration>* virtualChannelConfigurations);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -93,15 +108,26 @@ public:
|
|||
* same name or priority, the latter Channels with that name or priority will not be created.
|
||||
* @param activityTrackerInterface The interface to notify the activity tracker a vector of channel states that has
|
||||
* been updated.
|
||||
* @param virtualChannelConfigurations A vector of @c channelConfiguration objects that will be used to create the
|
||||
* Virtual Channels. No two Channels should have the same name or priority. If there are multiple configurations
|
||||
* with the same name or priority, the latter Channels with that name or priority will not be created.
|
||||
* @param interruptModel @c InterruptModel object that provides MixingBehavior inputs to ChannelObservers upon
|
||||
* Focus State Change.
|
||||
*/
|
||||
FocusManager(
|
||||
const std::vector<ChannelConfiguration> channelConfigurations,
|
||||
std::shared_ptr<ActivityTrackerInterface> activityTrackerInterface = nullptr);
|
||||
const std::vector<ChannelConfiguration>& channelConfigurations,
|
||||
std::shared_ptr<ActivityTrackerInterface> activityTrackerInterface = nullptr,
|
||||
const std::vector<ChannelConfiguration>& virtualChannelConfigurations = std::vector<ChannelConfiguration>(),
|
||||
std::shared_ptr<interruptModel::InterruptModel> interruptModel = nullptr);
|
||||
|
||||
bool acquireChannel(
|
||||
const std::string& channelName,
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface> channelObserver,
|
||||
const std::string& interface) override;
|
||||
const std::string& interfaceName) override;
|
||||
|
||||
bool acquireChannel(
|
||||
const std::string& channelName,
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> channelActivity) override;
|
||||
|
||||
std::future<bool> releaseChannel(
|
||||
const std::string& channelName,
|
||||
|
@ -116,6 +142,11 @@ public:
|
|||
void removeObserver(
|
||||
const std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerObserverInterface>& observer) override;
|
||||
|
||||
void modifyContentType(
|
||||
const std::string& channelName,
|
||||
const std::string& interfaceName,
|
||||
avsCommon::avs::ContentType contentType) override;
|
||||
|
||||
/**
|
||||
* Retrieves the default @c ChannelConfiguration for AVS audio channels.
|
||||
*
|
||||
|
@ -150,26 +181,40 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to read the @c ChannelConfiguration into @c m_allChannels. This function also ensures the name
|
||||
* and priority for all channels are unique.
|
||||
*
|
||||
* @param channelConfigurations The @c channelConfigurations of the channels.
|
||||
* @param isVirtual Whether the channels are virtual or not.
|
||||
*/
|
||||
void readChannelConfiguration(const std::vector<ChannelConfiguration>& channelConfigurations, bool isVirtual);
|
||||
|
||||
/**
|
||||
* Sets the @c FocusState for @c channel and notifies observers of the change.
|
||||
*
|
||||
* @param channel The @c Channel to set the @c FocusState for.
|
||||
* @param focus The @c FocusState to set @c channel to.
|
||||
* @param behavior The @c MixingBehavior to set @c channel to.
|
||||
* @param forceUpdate optional, if set to true this function will update
|
||||
* activitytracker context (even if focus/behavior did not change).
|
||||
*/
|
||||
void setChannelFocus(const std::shared_ptr<Channel>& channel, avsCommon::avs::FocusState focus);
|
||||
void setChannelFocus(
|
||||
const std::shared_ptr<Channel>& channel,
|
||||
avsCommon::avs::FocusState focus,
|
||||
avsCommon::avs::MixingBehavior behavior,
|
||||
bool forceUpdate = false);
|
||||
|
||||
/**
|
||||
* Grants access to the Channel specified and updates other Channels as needed. This function provides the full
|
||||
* implementation which the public method will call.
|
||||
*
|
||||
* @param channelToAcquire The Channel to acquire.
|
||||
* @param channelObserver The new observer of the Channel.
|
||||
* @param interface The name of the AVS inferface on the Channel.
|
||||
* @param channelActivity The Activity to acquire.
|
||||
*/
|
||||
void acquireChannelHelper(
|
||||
std::shared_ptr<Channel> channelToAcquire,
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface> channelObserver,
|
||||
const std::string& interface);
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> channelActivity);
|
||||
|
||||
/**
|
||||
* Releases the Channel specified and updates other Channels as needed. This function provides the full
|
||||
|
@ -261,6 +306,30 @@ private:
|
|||
*/
|
||||
void notifyActivityTracker();
|
||||
|
||||
/**
|
||||
* Get the mixing behavior for ChannelObserver associated with a low priority channel , when a high priority channel
|
||||
* barges in
|
||||
*
|
||||
* @param lowPrioChannel channel with the lower priority
|
||||
* @param highPrioChannel channel with the higher priority
|
||||
* @return MixingBehavior to be taken by the ChannelObserver associated with the lowPrioChannel
|
||||
*/
|
||||
avsCommon::avs::MixingBehavior getMixingBehavior(
|
||||
std::shared_ptr<Channel> lowPrioChannel,
|
||||
std::shared_ptr<Channel> highPrioChannel);
|
||||
|
||||
/**
|
||||
* This function determines the mixingBehavior for each backgrounded channel, when the @param foregroundChannel is
|
||||
* in Foreground. It also invokes the ChannelObserverInterface::onFocusChanged callback for each backgrounded
|
||||
* channel.
|
||||
*
|
||||
* @param foregroundChannel the channel currently holding foreground focus
|
||||
*/
|
||||
void setBackgroundChannelMixingBehavior(std::shared_ptr<Channel> foregroundChannel);
|
||||
|
||||
/// Mutex used to lock m_activeChannels, m_observers and Channels' interface name.
|
||||
std::mutex m_mutex;
|
||||
|
||||
/// Map of channel names to shared_ptrs of Channel objects and contains every channel.
|
||||
std::unordered_map<std::string, std::shared_ptr<Channel>> m_allChannels;
|
||||
|
||||
|
@ -270,9 +339,6 @@ private:
|
|||
/// The set of observers to notify about focus changes.
|
||||
std::unordered_set<std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerObserverInterface>> m_observers;
|
||||
|
||||
/// Mutex used to lock m_activeChannels, m_observers and Channels' interface name.
|
||||
std::mutex m_mutex;
|
||||
|
||||
/*
|
||||
* A vector of channel's State that has been updated due to @c acquireChannel(), @c releaseChannel() or
|
||||
* stopForegroundActivity(). This is accessed by functions in the @c m_executor worker thread, and do not require
|
||||
|
@ -283,6 +349,9 @@ private:
|
|||
/// The interface to notify its activity tracker of any changes to its channels.
|
||||
std::shared_ptr<ActivityTrackerInterface> m_activityTracker;
|
||||
|
||||
/// The interrupt Model associated with the focus manager
|
||||
std::shared_ptr<interruptModel::InterruptModel> m_interruptModel;
|
||||
|
||||
/**
|
||||
* @c Executor which queues up operations from asynchronous API calls.
|
||||
*
|
||||
|
|
|
@ -5,8 +5,8 @@ add_library(AFML SHARED
|
|||
VisualActivityTracker.cpp)
|
||||
|
||||
add_definitions("-DACSDK_LOG_MODULE=afml")
|
||||
include_directories(AFML "${AFML_SOURCE_DIR}/include")
|
||||
target_link_libraries(AFML AVSCommon)
|
||||
include_directories(AFML "${AFML_SOURCE_DIR}/include" "{InterruptModel_SOURCE_DIR}/include")
|
||||
target_link_libraries(AFML AVSCommon InterruptModel)
|
||||
|
||||
# install target
|
||||
asdk_install()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
#include "AFML/Channel.h"
|
||||
#include <AVSCommon/Utils/Logger/Logger.h>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace afml {
|
||||
|
@ -21,6 +22,16 @@ namespace afml {
|
|||
using namespace avsCommon::avs;
|
||||
using namespace avsCommon::sdkInterfaces;
|
||||
|
||||
/// String to identify log entries originating from this file.
|
||||
static const std::string TAG("Channel");
|
||||
|
||||
/**
|
||||
* Create a LogEntry using this file's TAG and the specified event string.
|
||||
*
|
||||
* @param The event string for this @c LogEntry.
|
||||
*/
|
||||
#define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event)
|
||||
|
||||
Channel::State::State(const std::string& name) :
|
||||
name{name},
|
||||
focusState{FocusState::NONE},
|
||||
|
@ -30,10 +41,10 @@ Channel::State::State(const std::string& name) :
|
|||
Channel::State::State() : focusState{FocusState::NONE}, timeAtIdle{std::chrono::steady_clock::now()} {
|
||||
}
|
||||
|
||||
Channel::Channel(const std::string& name, const unsigned int priority) :
|
||||
Channel::Channel(const std::string& name, const unsigned int priority, bool isVirtual) :
|
||||
m_priority{priority},
|
||||
m_state{name},
|
||||
m_observer{nullptr} {
|
||||
m_isVirtual{isVirtual},
|
||||
m_state{name} {
|
||||
}
|
||||
|
||||
const std::string& Channel::getName() const {
|
||||
|
@ -44,50 +55,291 @@ unsigned int Channel::getPriority() const {
|
|||
return m_priority;
|
||||
}
|
||||
|
||||
bool Channel::setFocus(FocusState focus) {
|
||||
if (focus == m_state.focusState) {
|
||||
bool Channel::setFocus(FocusState focus, MixingBehavior behavior, bool forceUpdate) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
bool focusChanged = (m_state.focusState != focus);
|
||||
auto primaryActivity = getPrimaryActivityLocked();
|
||||
bool mixingBehaviorChanged = primaryActivity && (primaryActivity->getMixingBehavior() != behavior);
|
||||
|
||||
if (!forceUpdate && !focusChanged && !mixingBehaviorChanged) {
|
||||
return false;
|
||||
}
|
||||
ACSDK_DEBUG5(LX(__func__)
|
||||
.d("name", m_state.name)
|
||||
.d("newfocusState", focus)
|
||||
.d("prevfocusState", m_state.focusState)
|
||||
.d("newMixingBehavior", behavior)
|
||||
.d("forceUpdate", forceUpdate));
|
||||
|
||||
m_state.focusState = focus;
|
||||
if (m_observer) {
|
||||
m_observer->onFocusChanged(m_state.focusState);
|
||||
}
|
||||
|
||||
if (FocusState::NONE == m_state.focusState) {
|
||||
m_observer = nullptr;
|
||||
if (m_state.focusState == FocusState::NONE) {
|
||||
m_state.timeAtIdle = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
// Update Channel State Updates
|
||||
addToChannelUpdatesLocked(m_state.interfaceName, m_state.focusState);
|
||||
lock.unlock();
|
||||
|
||||
// Notify all activities of the new focus state for this channel
|
||||
notifyActivities(behavior, focus);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Channel::setObserver(std::shared_ptr<ChannelObserverInterface> observer) {
|
||||
m_observer = observer;
|
||||
void Channel::setPrimaryActivity(std::shared_ptr<FocusManagerInterface::Activity> activity) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
if (!activity) {
|
||||
ACSDK_ERROR(LX("setPrimaryActivityFailed").m("Null Activity"));
|
||||
return;
|
||||
}
|
||||
|
||||
ACSDK_DEBUG5(LX(__func__).d("Interface", activity->getInterface()));
|
||||
if (!m_activities.empty()) {
|
||||
processPolicyLocked(activity, m_activities.front());
|
||||
}
|
||||
|
||||
// Establish the activity.
|
||||
m_activities.push_front(activity);
|
||||
updateChannelInterfaceLocked();
|
||||
}
|
||||
|
||||
bool Channel::hasObserver() const {
|
||||
return m_observer != nullptr;
|
||||
bool Channel::releaseActivity(std::shared_ptr<ChannelObserverInterface> observer) {
|
||||
if (observer == nullptr) {
|
||||
ACSDK_ERROR(LX("releaseActivityFailed").d("reason", "observer is null."));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
for (auto it = m_activities.begin(); it != m_activities.end(); ++it) {
|
||||
if ((*it)->getChannelObserver() == observer) {
|
||||
bool success = removeActivityHelperLocked(it);
|
||||
if (success) {
|
||||
// No change in observer or activity if remove fails.
|
||||
addToChannelUpdatesLocked(m_state.interfaceName, m_state.focusState);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
ACSDK_DEBUG0(LX("releaseActivityFailed").m("Observer not found"));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Channel::releaseActivity(const std::string& interfaceName) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
for (auto it = m_activities.begin(); it != m_activities.end(); ++it) {
|
||||
if ((*it)->getInterface() == interfaceName) {
|
||||
bool success = removeActivityHelperLocked(it);
|
||||
if (success) {
|
||||
// Update Channel State Updates.
|
||||
addToChannelUpdatesLocked(m_state.interfaceName, m_state.focusState);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Channel::isActive() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
return !m_activities.empty();
|
||||
}
|
||||
|
||||
bool Channel::operator>(const Channel& rhs) const {
|
||||
return m_priority < rhs.getPriority();
|
||||
}
|
||||
|
||||
void Channel::setInterface(const std::string& interface) {
|
||||
m_state.interfaceName = interface;
|
||||
}
|
||||
|
||||
std::string Channel::getInterface() const {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return m_state.interfaceName;
|
||||
}
|
||||
|
||||
bool Channel::doesObserverOwnChannel(std::shared_ptr<ChannelObserverInterface> observer) const {
|
||||
return observer == m_observer;
|
||||
}
|
||||
|
||||
Channel::State Channel::getState() const {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return m_state;
|
||||
}
|
||||
|
||||
std::vector<Channel::State> Channel::getActivityUpdates() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
auto activityUpdatesRet = m_activityUpdates;
|
||||
m_activityUpdates.clear();
|
||||
return activityUpdatesRet;
|
||||
}
|
||||
|
||||
std::shared_ptr<FocusManagerInterface::Activity> Channel::getPrimaryActivity() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
return getPrimaryActivityLocked();
|
||||
}
|
||||
|
||||
std::shared_ptr<FocusManagerInterface::Activity> Channel::getPrimaryActivityLocked() const {
|
||||
if (m_activities.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return *(m_activities.begin());
|
||||
}
|
||||
|
||||
std::shared_ptr<FocusManagerInterface::Activity> Channel::getActivity(const std::string& interfaceName) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
for (const auto& it : m_activities) {
|
||||
if (it->getInterface() == interfaceName) return it;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> Channel::getInterfaceList() const {
|
||||
std::vector<std::string> listOfInterface = {};
|
||||
for (const auto& activity : m_activities) {
|
||||
listOfInterface.push_back(activity->getInterface());
|
||||
}
|
||||
return listOfInterface;
|
||||
}
|
||||
|
||||
void Channel::notifyActivities(MixingBehavior behavior, FocusState focusState) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (m_activities.empty()) {
|
||||
ACSDK_WARN(LX("notifyActivitiesFailed").m("No Associated Activities Found"));
|
||||
return;
|
||||
}
|
||||
auto activitiesCopy = m_activities;
|
||||
lock.unlock();
|
||||
|
||||
auto activityIt = activitiesCopy.begin();
|
||||
// inform the primary activity with the MixingBehavior
|
||||
(*activityIt)->notifyObserver(focusState, behavior);
|
||||
activityIt++;
|
||||
|
||||
// all other secondary activities must be PAUSED + BACKGROUND
|
||||
for (; activityIt != activitiesCopy.end(); activityIt++) {
|
||||
(*activityIt)->notifyObserver(FocusState::BACKGROUND, MixingBehavior::MUST_PAUSE);
|
||||
}
|
||||
}
|
||||
|
||||
bool Channel::releaseActivityLocked(
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> activityToRelease) {
|
||||
if (!activityToRelease) {
|
||||
ACSDK_ERROR(LX("releaseActivityLockedFailed").m("Null activityToRelease"));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto priorActivityIt = std::find(m_activities.begin(), m_activities.end(), activityToRelease);
|
||||
if (priorActivityIt != m_activities.end()) {
|
||||
return removeActivityHelperLocked(priorActivityIt);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Channel::removeActivityHelperLocked(
|
||||
std::list<std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity>>::iterator
|
||||
activityToRemoveIt) {
|
||||
ACSDK_DEBUG5(LX(__func__).d("interface", (*activityToRemoveIt)->getInterface()));
|
||||
|
||||
auto isRemovingPatienceReceiver = false;
|
||||
if (m_patienceReceiver == *activityToRemoveIt) {
|
||||
isRemovingPatienceReceiver = true;
|
||||
}
|
||||
|
||||
// Timer is active AND the job being removed is one of the patience Activities.
|
||||
if (m_patienceTimer.isActive() &&
|
||||
(m_patienceInitiator == *activityToRemoveIt || m_patienceReceiver == *activityToRemoveIt)) {
|
||||
m_patienceTimer.stop();
|
||||
ACSDK_DEBUG9(LX(__func__).d("status", "Patience Timer Stopped"));
|
||||
m_patienceInitiator = nullptr;
|
||||
m_patienceReceiver = nullptr;
|
||||
}
|
||||
|
||||
// If the activity to remove is the last activity, then update the time at idle for this channel
|
||||
if (m_activities.size() == 1) {
|
||||
m_state.timeAtIdle = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
// No need to update Channel updates for removing patience receiver.
|
||||
if (!isRemovingPatienceReceiver) {
|
||||
// Add the current State and override the FocusState with NONE.
|
||||
addToChannelUpdatesLocked((*activityToRemoveIt)->getInterface(), FocusState::NONE);
|
||||
}
|
||||
|
||||
// Report NONE only to the single Activity that is removed
|
||||
(*activityToRemoveIt)->notifyObserver(FocusState::NONE, MixingBehavior::MUST_STOP);
|
||||
m_activities.erase(activityToRemoveIt);
|
||||
updateChannelInterfaceLocked();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Channel::addToChannelUpdatesLocked(const std::string& interfaceName, avsCommon::avs::FocusState focusState) {
|
||||
if (m_state.interfaceName.empty()) {
|
||||
return;
|
||||
}
|
||||
// Only add to Channel updates if channel is not virtual.
|
||||
if (!m_isVirtual) {
|
||||
auto state = m_state;
|
||||
state.focusState = focusState;
|
||||
state.interfaceName = interfaceName;
|
||||
m_activityUpdates.push_back(state);
|
||||
ACSDK_DEBUG0(LX(__func__).d("interface", state.interfaceName).d("focusState", state.focusState));
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::processPolicyLocked(
|
||||
std::shared_ptr<FocusManagerInterface::Activity> incomingActivity,
|
||||
std::shared_ptr<FocusManagerInterface::Activity> currentActivity) {
|
||||
if (!incomingActivity || !currentActivity) {
|
||||
ACSDK_ERROR(LX("processPolicyLockedFailed").m("Null Activities"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (incomingActivity->getInterface() == currentActivity->getInterface()) {
|
||||
// Both incoming and current activity has identical interface. Remove the current activity regardless of policy.
|
||||
releaseActivityLocked(currentActivity);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_patienceTimer.isActive()) {
|
||||
// A new Activity is incoming. If there is an ongoing patience release, remove the receiver immediately.
|
||||
// Any persistent initiator or receiver will not be removed.
|
||||
m_patienceTimer.stop();
|
||||
ACSDK_DEBUG9(LX(__func__).d("status", "Patience Release Timer Stopped"));
|
||||
releaseActivityLocked(m_patienceReceiver);
|
||||
m_patienceReceiver = nullptr;
|
||||
}
|
||||
|
||||
if (incomingActivity->getPatienceDuration().count() > 0) {
|
||||
// Incoming valid patience Activity
|
||||
ACSDK_DEBUG9(LX(__func__).d("status", "Patience Timer Started"));
|
||||
addToChannelUpdatesLocked(currentActivity->getInterface(), FocusState::NONE);
|
||||
auto patienceDuration = incomingActivity->getPatienceDuration();
|
||||
m_patienceTimer.start(patienceDuration, std::bind(&Channel::patienceTimerCallback, this, currentActivity));
|
||||
m_patienceInitiator = incomingActivity;
|
||||
m_patienceReceiver = currentActivity;
|
||||
} else {
|
||||
if (m_patienceInitiator != nullptr) {
|
||||
// No valid patience duration, release the initiator.
|
||||
releaseActivityLocked(m_patienceInitiator);
|
||||
m_patienceInitiator = nullptr;
|
||||
}
|
||||
releaseActivityLocked(currentActivity);
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::patienceTimerCallback(
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> activity) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
ACSDK_DEBUG9(LX(__func__).d("status", "Patience Release Timer Triggered"));
|
||||
releaseActivityLocked(std::move(activity));
|
||||
// No need to modify channel updates since it was Already reported
|
||||
// when patienceInitiator came into focus.
|
||||
}
|
||||
|
||||
void Channel::updateChannelInterfaceLocked() {
|
||||
if (!m_activities.empty()) {
|
||||
m_state.interfaceName = m_activities.front()->getInterface();
|
||||
} else {
|
||||
m_state.interfaceName = "";
|
||||
}
|
||||
}
|
||||
} // namespace afml
|
||||
} // namespace alexaClientSDK
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -13,6 +13,8 @@
|
|||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "AFML/FocusManager.h"
|
||||
#include <AVSCommon/Utils/Logger/Logger.h>
|
||||
|
||||
|
@ -22,10 +24,20 @@ namespace afml {
|
|||
using namespace avsCommon::sdkInterfaces;
|
||||
using namespace avsCommon::utils;
|
||||
using namespace avsCommon::avs;
|
||||
using namespace interruptModel;
|
||||
|
||||
/// String to identify log entries originating from this file.
|
||||
static const std::string TAG("FocusManager");
|
||||
|
||||
/// Key for @c FocusManager configurations in configuration node.
|
||||
static const std::string VIRTUAL_CHANNELS_CONFIG_KEY = "virtualChannels";
|
||||
|
||||
/// Key for the name of the channel in configuration node.
|
||||
static const std::string CHANNEL_NAME_KEY = "name";
|
||||
|
||||
/// Key for the priority of the channel in configuration node.
|
||||
static const std::string CHANNEL_PRIORITY_KEY = "priority";
|
||||
|
||||
/**
|
||||
* Create a LogEntry using this file's TAG and the specified event string.
|
||||
*
|
||||
|
@ -34,38 +46,57 @@ static const std::string TAG("FocusManager");
|
|||
#define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event)
|
||||
|
||||
FocusManager::FocusManager(
|
||||
const std::vector<ChannelConfiguration> channelConfigurations,
|
||||
std::shared_ptr<ActivityTrackerInterface> activityTrackerInterface) :
|
||||
m_activityTracker{activityTrackerInterface} {
|
||||
for (auto config : channelConfigurations) {
|
||||
if (doesChannelNameExist(config.name)) {
|
||||
ACSDK_ERROR(LX("createChannelFailed").d("reason", "channelNameExists").d("config", config.toString()));
|
||||
continue;
|
||||
}
|
||||
if (doesChannelPriorityExist(config.priority)) {
|
||||
ACSDK_ERROR(LX("createChannelFailed").d("reason", "channelPriorityExists").d("config", config.toString()));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto channel = std::make_shared<Channel>(config.name, config.priority);
|
||||
m_allChannels.insert({config.name, channel});
|
||||
}
|
||||
const std::vector<ChannelConfiguration>& channelConfigurations,
|
||||
std::shared_ptr<ActivityTrackerInterface> activityTrackerInterface,
|
||||
const std::vector<ChannelConfiguration>& virtualChannelConfigurations,
|
||||
std::shared_ptr<InterruptModel> interruptModel) :
|
||||
m_activityTracker{activityTrackerInterface},
|
||||
m_interruptModel{interruptModel} {
|
||||
// Read AVS channel configurations.
|
||||
readChannelConfiguration(channelConfigurations, false);
|
||||
// Read virtual channel configurations.
|
||||
readChannelConfiguration(virtualChannelConfigurations, true);
|
||||
}
|
||||
|
||||
bool FocusManager::acquireChannel(
|
||||
const std::string& channelName,
|
||||
std::shared_ptr<ChannelObserverInterface> channelObserver,
|
||||
const std::string& interface) {
|
||||
ACSDK_DEBUG1(LX("acquireChannel").d("channelName", channelName).d("interface", interface));
|
||||
const std::string& interfaceName) {
|
||||
ACSDK_DEBUG1(LX("acquireChannel").d("channelName", channelName).d("interface", interfaceName));
|
||||
std::shared_ptr<Channel> channelToAcquire = getChannel(channelName);
|
||||
if (!channelToAcquire) {
|
||||
ACSDK_ERROR(LX("acquireChannelFailed").d("reason", "channelNotFound").d("channelName", channelName));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_executor.submit([this, channelToAcquire, channelObserver, interface]() {
|
||||
acquireChannelHelper(channelToAcquire, channelObserver, interface);
|
||||
});
|
||||
auto channelActivity = FocusManagerInterface::Activity::create(interfaceName, channelObserver);
|
||||
if (!channelActivity) {
|
||||
ACSDK_ERROR(LX("acquireChannelFailed").d("reason", "failedToCreateActivity").d("interface", interfaceName));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_executor.submit(
|
||||
[this, channelToAcquire, channelActivity]() { acquireChannelHelper(channelToAcquire, channelActivity); });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FocusManager::acquireChannel(
|
||||
const std::string& channelName,
|
||||
std::shared_ptr<FocusManagerInterface::Activity> channelActivity) {
|
||||
ACSDK_DEBUG1(LX("acquireChannel").d("channelName", channelName).d("interface", channelActivity->getInterface()));
|
||||
std::shared_ptr<Channel> channelToAcquire = getChannel(channelName);
|
||||
if (!channelToAcquire) {
|
||||
ACSDK_ERROR(LX("acquireChannelFailed").d("reason", "channelNotFound").d("channelName", channelName));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!channelActivity) {
|
||||
ACSDK_ERROR(LX("acquireChannelFailed").d("reason", "channelActivityIsNull"));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_executor.submit(
|
||||
[this, channelToAcquire, channelActivity]() { acquireChannelHelper(channelToAcquire, channelActivity); });
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -120,7 +151,9 @@ void FocusManager::stopAllActivities() {
|
|||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
for (const auto& channel : m_activeChannels) {
|
||||
channelOwnersCapture.insert(std::pair<std::shared_ptr<Channel>, std::string>(channel, channel->getInterface()));
|
||||
for (const auto& interfaceName : channel->getInterfaceList()) {
|
||||
channelOwnersCapture.insert(std::pair<std::shared_ptr<Channel>, std::string>(channel, interfaceName));
|
||||
}
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
@ -138,46 +171,125 @@ void FocusManager::removeObserver(const std::shared_ptr<FocusManagerObserverInte
|
|||
m_observers.erase(observer);
|
||||
}
|
||||
|
||||
void FocusManager::setChannelFocus(const std::shared_ptr<Channel>& channel, FocusState focus) {
|
||||
if (!channel->setFocus(focus)) {
|
||||
void FocusManager::readChannelConfiguration(
|
||||
const std::vector<ChannelConfiguration>& channelConfigurations,
|
||||
bool isVirtual) {
|
||||
for (const auto& config : channelConfigurations) {
|
||||
if (doesChannelNameExist(config.name)) {
|
||||
ACSDK_ERROR(
|
||||
LX("readChannelConfigurationFailed").d("reason", "channelNameExists").d("config", config.toString()));
|
||||
continue;
|
||||
}
|
||||
if (doesChannelPriorityExist(config.priority)) {
|
||||
ACSDK_ERROR(LX("readChannelConfigurationFailed")
|
||||
.d("reason", "channelPriorityExists")
|
||||
.d("config", config.toString()));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto channel = std::make_shared<Channel>(config.name, config.priority, isVirtual);
|
||||
m_allChannels.insert({config.name, channel});
|
||||
}
|
||||
}
|
||||
|
||||
void FocusManager::setChannelFocus(
|
||||
const std::shared_ptr<Channel>& channel,
|
||||
FocusState focus,
|
||||
MixingBehavior behavior,
|
||||
bool forceUpdate) {
|
||||
if (!channel->setFocus(focus, behavior, forceUpdate)) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
// take a copy of the observers
|
||||
auto observers = m_observers;
|
||||
lock.unlock();
|
||||
|
||||
// inform copy of the observers in an unlocked content
|
||||
for (auto& observer : observers) {
|
||||
observer->onFocusChanged(channel->getName(), focus);
|
||||
}
|
||||
m_activityUpdates.push_back(channel->getState());
|
||||
}
|
||||
|
||||
MixingBehavior FocusManager::getMixingBehavior(
|
||||
std::shared_ptr<Channel> lowPrioChannel,
|
||||
std::shared_ptr<Channel> highPrioChannel) {
|
||||
if (!m_interruptModel) {
|
||||
ACSDK_ERROR(LX(__func__).m("Null InterruptModel"));
|
||||
return MixingBehavior::UNDEFINED;
|
||||
}
|
||||
|
||||
if (!lowPrioChannel || !highPrioChannel) {
|
||||
ACSDK_ERROR(LX("getMixingBehaviorFailed").d("reason", "nullInputChannels"));
|
||||
return MixingBehavior::UNDEFINED;
|
||||
}
|
||||
|
||||
if (*lowPrioChannel > *highPrioChannel) {
|
||||
ACSDK_ERROR(LX("getMixingBehaviorFailed")
|
||||
.d("reason", "Priorities of input channels violate API contract")
|
||||
.d("lowPrioChannel priority", lowPrioChannel->getPriority())
|
||||
.d("highPrioChannel priority", highPrioChannel->getPriority()));
|
||||
return MixingBehavior::UNDEFINED;
|
||||
}
|
||||
|
||||
auto lowPrioChannelName = lowPrioChannel->getName();
|
||||
auto lowPrioChannelPrimaryActivity = lowPrioChannel->getPrimaryActivity();
|
||||
if (!lowPrioChannelPrimaryActivity) {
|
||||
ACSDK_ERROR(LX("getMixingBehaviorFailed").d("No PrimaryActivity on lowPrioChannel", lowPrioChannelName));
|
||||
return MixingBehavior::UNDEFINED;
|
||||
}
|
||||
|
||||
auto highPrioChannelName = highPrioChannel->getName();
|
||||
auto highPrioChannelPrimaryActivity = highPrioChannel->getPrimaryActivity();
|
||||
if (!highPrioChannelPrimaryActivity) {
|
||||
ACSDK_ERROR(LX("getMixingBehaviorFailed").d("No PrimaryActivity on highPrioChannel", highPrioChannelName));
|
||||
return MixingBehavior::UNDEFINED;
|
||||
}
|
||||
|
||||
return m_interruptModel->getMixingBehavior(
|
||||
lowPrioChannelName,
|
||||
lowPrioChannelPrimaryActivity->getContentType(),
|
||||
highPrioChannelName,
|
||||
highPrioChannelPrimaryActivity->getContentType());
|
||||
}
|
||||
|
||||
void FocusManager::acquireChannelHelper(
|
||||
std::shared_ptr<Channel> channelToAcquire,
|
||||
std::shared_ptr<ChannelObserverInterface> channelObserver,
|
||||
const std::string& interface) {
|
||||
// Notify the old observer, if there is one, that it lost focus.
|
||||
setChannelFocus(channelToAcquire, FocusState::NONE);
|
||||
|
||||
std::shared_ptr<FocusManagerInterface::Activity> channelActivity) {
|
||||
// Lock here to update internal state which stopForegroundActivity may concurrently access.
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
std::shared_ptr<Channel> foregroundChannel = getHighestPriorityActiveChannelLocked();
|
||||
channelToAcquire->setInterface(interface);
|
||||
// insert the incoming channel
|
||||
m_activeChannels.insert(channelToAcquire);
|
||||
lock.unlock();
|
||||
|
||||
// Set the new observer.
|
||||
channelToAcquire->setObserver(channelObserver);
|
||||
ACSDK_DEBUG5(LX(__func__)
|
||||
.d("incomingChannel", channelToAcquire->getName())
|
||||
.d("incomingInterface", channelActivity->getInterface()));
|
||||
|
||||
// attach Activity to the Channel
|
||||
channelToAcquire->setPrimaryActivity(std::move(channelActivity));
|
||||
|
||||
if (!foregroundChannel) {
|
||||
setChannelFocus(channelToAcquire, FocusState::FOREGROUND);
|
||||
// channelToAcquire is the only active channel
|
||||
setChannelFocus(channelToAcquire, FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
} else if (foregroundChannel == channelToAcquire) {
|
||||
setChannelFocus(channelToAcquire, FocusState::FOREGROUND);
|
||||
// acquireChannel request is for the same channel as the current foreground channel
|
||||
// NOTE : the primaryActivity interface may change , even though focus state has not changed for the channel
|
||||
setChannelFocus(channelToAcquire, FocusState::FOREGROUND, MixingBehavior::PRIMARY, true);
|
||||
} else if (*channelToAcquire > *foregroundChannel) {
|
||||
setChannelFocus(foregroundChannel, FocusState::BACKGROUND);
|
||||
setChannelFocus(channelToAcquire, FocusState::FOREGROUND);
|
||||
// channelToAcquire will now become the foreground channel, other channels shall be backgrounded
|
||||
// For each background channel : consult interrupt model to determine the mixability
|
||||
setBackgroundChannelMixingBehavior(channelToAcquire);
|
||||
|
||||
// set channelToAcquire as Foreground
|
||||
setChannelFocus(channelToAcquire, FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
} else {
|
||||
setChannelFocus(channelToAcquire, FocusState::BACKGROUND);
|
||||
// channelToAcquire is to be backgrounded
|
||||
auto mixingBehavior = getMixingBehavior(channelToAcquire, foregroundChannel);
|
||||
setChannelFocus(channelToAcquire, FocusState::BACKGROUND, mixingBehavior);
|
||||
}
|
||||
|
||||
notifyActivityTracker();
|
||||
}
|
||||
|
||||
|
@ -186,23 +298,28 @@ void FocusManager::releaseChannelHelper(
|
|||
std::shared_ptr<ChannelObserverInterface> channelObserver,
|
||||
std::shared_ptr<std::promise<bool>> releaseChannelSuccess,
|
||||
const std::string& name) {
|
||||
if (!channelToRelease->doesObserverOwnChannel(channelObserver)) {
|
||||
ACSDK_ERROR(LX("releaseChannelHelperFailed").d("reason", "observerDoesNotOwnChannel").d("channel", name));
|
||||
releaseChannelSuccess->set_value(false);
|
||||
ACSDK_DEBUG5(LX(__func__).d("channelToRelease", channelToRelease->getName()));
|
||||
|
||||
bool success = channelToRelease->releaseActivity(std::move(channelObserver));
|
||||
releaseChannelSuccess->set_value(success);
|
||||
|
||||
if (!success) {
|
||||
ACSDK_ERROR(LX(__func__)
|
||||
.d("reason", "releaseActivityFailed")
|
||||
.d("channel", channelToRelease)
|
||||
.d("interface", channelToRelease->getInterface()));
|
||||
return;
|
||||
}
|
||||
|
||||
releaseChannelSuccess->set_value(true);
|
||||
// Lock here to update internal state which stopForegroundActivity may concurrently access.
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
bool wasForegrounded = isChannelForegroundedLocked(channelToRelease);
|
||||
m_activeChannels.erase(channelToRelease);
|
||||
lock.unlock();
|
||||
|
||||
setChannelFocus(channelToRelease, FocusState::NONE);
|
||||
if (wasForegrounded) {
|
||||
foregroundHighestPriorityActiveChannel();
|
||||
// Only release and set entire channel focus to NONE if there are no active Activity remaining.
|
||||
if (!channelToRelease->isActive()) {
|
||||
// Lock here to update internal state which stopForegroundActivity may concurrently access.
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_activeChannels.erase(channelToRelease);
|
||||
lock.unlock();
|
||||
setChannelFocus(channelToRelease, FocusState::NONE, MixingBehavior::MUST_STOP);
|
||||
}
|
||||
foregroundHighestPriorityActiveChannel();
|
||||
notifyActivityTracker();
|
||||
}
|
||||
|
||||
|
@ -212,15 +329,24 @@ void FocusManager::stopForegroundActivityHelper(
|
|||
if (foregroundChannelInterface != foregroundChannel->getInterface()) {
|
||||
return;
|
||||
}
|
||||
if (!foregroundChannel->hasObserver()) {
|
||||
return;
|
||||
ACSDK_DEBUG5(LX(__func__).d("interface", foregroundChannelInterface));
|
||||
bool success = foregroundChannel->releaseActivity(foregroundChannel->getInterface());
|
||||
if (!success) {
|
||||
ACSDK_ERROR(LX(__func__)
|
||||
.d("reason", "releaseActivityFailed")
|
||||
.d("channel", foregroundChannel)
|
||||
.d("interface", foregroundChannel->getInterface()));
|
||||
}
|
||||
setChannelFocus(foregroundChannel, FocusState::NONE);
|
||||
|
||||
// Lock here to update internal state which stopForegroundActivity may concurrently access.
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_activeChannels.erase(foregroundChannel);
|
||||
lock.unlock();
|
||||
// Only release and set entire channel focus to NONE if there are no active Activity remaining.
|
||||
if (!foregroundChannel->isActive()) {
|
||||
ACSDK_DEBUG1(LX(__func__).m("Channel is not active ... releasing"));
|
||||
// Lock here to update internal state which stopForegroundActivity may concurrently access.
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_activeChannels.erase(foregroundChannel);
|
||||
lock.unlock();
|
||||
setChannelFocus(foregroundChannel, FocusState::NONE, MixingBehavior::MUST_STOP);
|
||||
}
|
||||
foregroundHighestPriorityActiveChannel();
|
||||
notifyActivityTracker();
|
||||
}
|
||||
|
@ -233,22 +359,29 @@ void FocusManager::stopAllActivitiesHelper(const ChannelsToInterfaceNamesMap& ch
|
|||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
for (const auto& channelAndInterface : channelsOwnersMap) {
|
||||
if (channelAndInterface.first->getInterface() == channelAndInterface.second) {
|
||||
m_activeChannels.erase(channelAndInterface.first);
|
||||
channelsToClear.insert(channelAndInterface.first);
|
||||
} else {
|
||||
ACSDK_INFO(LX(__func__)
|
||||
.d("reason", "channel has other ownership")
|
||||
.d("channel", channelAndInterface.first->getName())
|
||||
.d("currentInterface", channelAndInterface.first->getInterface())
|
||||
.d("originalInterface", channelAndInterface.second));
|
||||
auto channel = channelAndInterface.first;
|
||||
auto interfaceName = channelAndInterface.second;
|
||||
ACSDK_DEBUG3(LX(__func__).d("channel", channel).d("interface", interfaceName));
|
||||
|
||||
bool success = channel->releaseActivity(channelAndInterface.second);
|
||||
if (!success) {
|
||||
ACSDK_ERROR(
|
||||
LX(__func__).d("reason", "releaseActivityFailed").d("channel", channel).d("interface", interfaceName));
|
||||
}
|
||||
channelsToClear.insert(channel);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
||||
for (const auto& channel : channelsToClear) {
|
||||
setChannelFocus(channel, FocusState::NONE);
|
||||
// Only release and set entire channel focus to NONE if there are no active Activity remaining.
|
||||
if (!channel->isActive()) {
|
||||
// Lock here to update internal state which stopForegroundActivity may concurrently access.
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_activeChannels.erase(channel);
|
||||
lock.unlock();
|
||||
setChannelFocus(channel, FocusState::NONE, MixingBehavior::MUST_STOP);
|
||||
}
|
||||
}
|
||||
foregroundHighestPriorityActiveChannel();
|
||||
notifyActivityTracker();
|
||||
|
@ -278,26 +411,97 @@ bool FocusManager::doesChannelNameExist(const std::string& name) const {
|
|||
}
|
||||
|
||||
bool FocusManager::doesChannelPriorityExist(const unsigned int priority) const {
|
||||
for (auto it = m_allChannels.begin(); it != m_allChannels.end(); ++it) {
|
||||
if (it->second->getPriority() == priority) {
|
||||
for (const auto& m_allChannel : m_allChannels) {
|
||||
if (m_allChannel.second->getPriority() == priority) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FocusManager::modifyContentType(
|
||||
const std::string& channelName,
|
||||
const std::string& interfaceName,
|
||||
ContentType contentType) {
|
||||
// find the channel
|
||||
auto channel = getChannel(channelName);
|
||||
if (!channel) {
|
||||
ACSDK_ERROR(LX("modifyContentTypeFailed").d("reason", "channelNotFound").d("channel", channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
// find the activity associated with the interfacename in the channel
|
||||
auto activity = channel->getActivity(interfaceName);
|
||||
if (!activity) {
|
||||
ACSDK_ERROR(LX("modifyContentTypeFailed").d("no activity found associated with interfaceName", interfaceName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (contentType == activity->getContentType()) {
|
||||
ACSDK_WARN(LX("modifyContentTypeFailed").d("no contentType to modify it is already identical: ", contentType));
|
||||
return;
|
||||
}
|
||||
|
||||
// modify the contentType associated with the activity
|
||||
activity->setContentType(contentType);
|
||||
|
||||
// reconsult the InterruptModel and set the new MixingBehaviors for all backgrounded channelobservers
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
std::shared_ptr<Channel> foregroundChannel = getHighestPriorityActiveChannelLocked();
|
||||
lock.unlock();
|
||||
setBackgroundChannelMixingBehavior(foregroundChannel);
|
||||
}
|
||||
|
||||
void FocusManager::setBackgroundChannelMixingBehavior(std::shared_ptr<Channel> foregroundChannel) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
auto channelIter = m_activeChannels.find(foregroundChannel);
|
||||
if (channelIter == m_activeChannels.end()) {
|
||||
ACSDK_ERROR(
|
||||
LX("setBackgroundChannelMixingBehaviorFailed").d("Could not find channel", foregroundChannel->getName()));
|
||||
return;
|
||||
}
|
||||
// skip to the next channel in priority
|
||||
channelIter++;
|
||||
|
||||
for (; channelIter != m_activeChannels.end(); channelIter++) {
|
||||
// determine mixingBehavior for each background channel
|
||||
auto mixingBehavior = getMixingBehavior(*channelIter, foregroundChannel);
|
||||
lock.unlock();
|
||||
setChannelFocus(*channelIter, FocusState::BACKGROUND, mixingBehavior);
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
void FocusManager::foregroundHighestPriorityActiveChannel() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
std::shared_ptr<Channel> channelToForeground = getHighestPriorityActiveChannelLocked();
|
||||
lock.unlock();
|
||||
|
||||
if (channelToForeground) {
|
||||
setChannelFocus(channelToForeground, FocusState::FOREGROUND);
|
||||
// inform background channels of the new MixingBehavior as per the new Foreground Channel
|
||||
setBackgroundChannelMixingBehavior(channelToForeground);
|
||||
|
||||
// Foreground the highest priority channel
|
||||
setChannelFocus(channelToForeground, FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
}
|
||||
}
|
||||
|
||||
void FocusManager::notifyActivityTracker() {
|
||||
if (m_activityTracker) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
for (const auto& channel : m_allChannels) {
|
||||
auto activityUpdates = channel.second->getActivityUpdates();
|
||||
for (const auto& activity : activityUpdates) {
|
||||
m_activityUpdates.push_back(activity);
|
||||
ACSDK_DEBUG1(LX(__func__)
|
||||
.d("name", activity.name)
|
||||
.d("interfaceName", activity.interfaceName)
|
||||
.d("focusState", activity.focusState));
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
if (m_activityTracker && !m_activityUpdates.empty()) {
|
||||
m_activityTracker->notifyOfActivityUpdates(m_activityUpdates);
|
||||
}
|
||||
m_activityUpdates.clear();
|
||||
|
@ -320,5 +524,59 @@ const std::vector<FocusManager::ChannelConfiguration> FocusManager::getDefaultVi
|
|||
return defaultVisualChannels;
|
||||
}
|
||||
|
||||
bool afml::FocusManager::ChannelConfiguration::readChannelConfiguration(
|
||||
const std::string& channelTypeKey,
|
||||
std::vector<afml::FocusManager::ChannelConfiguration>* virtualChannelConfigurations) {
|
||||
if (!virtualChannelConfigurations) {
|
||||
ACSDK_ERROR(LX("readChannelConfigurationFailed").d("reason", "nullVirtualChannelConfiguration"));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto configRoot =
|
||||
alexaClientSDK::avsCommon::utils::configuration::ConfigurationNode::getRoot()[VIRTUAL_CHANNELS_CONFIG_KEY];
|
||||
if (!configRoot) {
|
||||
ACSDK_DEBUG9(LX(__func__).m("noConfigurationRoot"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool returnValue = true;
|
||||
auto channelArray = configRoot.getArray(channelTypeKey);
|
||||
if (!channelArray) {
|
||||
ACSDK_DEBUG9(LX(__func__).d("key", channelTypeKey).m("keyNotFoundOrNotAnArray"));
|
||||
} else {
|
||||
for (std::size_t i = 0; i < channelArray.getArraySize(); i++) {
|
||||
auto elem = channelArray[i];
|
||||
if (!elem) {
|
||||
ACSDK_ERROR(LX("readChannelConfigurationFailed").d("reason", "noNameKey"));
|
||||
returnValue = false;
|
||||
break;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
if (!elem.getString(CHANNEL_NAME_KEY, &name)) {
|
||||
ACSDK_ERROR(LX("readChannelConfigurationFailed").d("reason", "noNameKey"));
|
||||
returnValue = false;
|
||||
break;
|
||||
}
|
||||
|
||||
int priority = 0;
|
||||
if (!elem.getInt(CHANNEL_PRIORITY_KEY, &priority)) {
|
||||
ACSDK_ERROR(LX("readChannelConfigurationFailed").d("reason", "noPriorityKey"));
|
||||
returnValue = false;
|
||||
break;
|
||||
}
|
||||
if (priority < 0) {
|
||||
ACSDK_ERROR(LX("ChannelConfigurationFailed").d("reason", "invalidPriority").d("priority", priority));
|
||||
returnValue = false;
|
||||
break;
|
||||
}
|
||||
|
||||
afml::FocusManager::ChannelConfiguration channelConfig{name, static_cast<unsigned int>(priority)};
|
||||
virtualChannelConfigurations->push_back(channelConfig);
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
} // namespace afml
|
||||
} // namespace alexaClientSDK
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -44,7 +44,7 @@ using namespace avsCommon::utils::json;
|
|||
using namespace ::testing;
|
||||
|
||||
/// Plenty of time for a test to complete.
|
||||
static std::chrono::milliseconds WAIT_TIMEOUT(1000);
|
||||
static std::chrono::milliseconds MY_WAIT_TIMEOUT(1000);
|
||||
|
||||
/// Namespace for AudioActivityTracke.
|
||||
static const std::string NAMESPACE_AUDIO_ACTIVITY_TRACKER("AudioActivityTracker");
|
||||
|
@ -79,6 +79,13 @@ static unsigned int CONTENT_CHANNEL_PRIORITY{300};
|
|||
/// Timeout to sleep before asking for provideState().
|
||||
static const std::chrono::milliseconds SHORT_TIMEOUT_MS = std::chrono::milliseconds(5);
|
||||
|
||||
/// MockChannelObserver for tests
|
||||
class MockChannelObserver : public avsCommon::sdkInterfaces::ChannelObserverInterface {
|
||||
public:
|
||||
void onFocusChanged(avsCommon::avs::FocusState state, avsCommon::avs::MixingBehavior behavior) override {
|
||||
}
|
||||
};
|
||||
|
||||
class AudioActivityTrackerTest : public ::testing::Test {
|
||||
public:
|
||||
AudioActivityTrackerTest();
|
||||
|
@ -139,11 +146,9 @@ void AudioActivityTrackerTest::SetUp() {
|
|||
ASSERT_TRUE(m_mockContextManager != nullptr);
|
||||
|
||||
m_dialogChannel = std::make_shared<Channel>(DIALOG_CHANNEL_NAME, DIALOG_CHANNEL_PRIORITY);
|
||||
m_dialogChannel->setInterface(DIALOG_INTERFACE_NAME);
|
||||
ASSERT_TRUE(m_dialogChannel != nullptr);
|
||||
|
||||
m_contentChannel = std::make_shared<Channel>(CONTENT_CHANNEL_NAME, CONTENT_CHANNEL_PRIORITY);
|
||||
m_contentChannel->setInterface(CONTENT_INTERFACE_NAME);
|
||||
ASSERT_TRUE(m_contentChannel != nullptr);
|
||||
}
|
||||
|
||||
|
@ -207,7 +212,7 @@ void AudioActivityTrackerTest::provideUpdate(const std::vector<Channel::State>&
|
|||
m_audioActivityTracker->notifyOfActivityUpdates(channels);
|
||||
std::this_thread::sleep_for(SHORT_TIMEOUT_MS);
|
||||
m_audioActivityTracker->provideState(NAMESPACE_AND_NAME_STATE, PROVIDE_STATE_TOKEN_TEST);
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
|
||||
}
|
||||
|
||||
SetStateResult AudioActivityTrackerTest::wakeOnSetState() {
|
||||
|
@ -224,7 +229,7 @@ TEST_F(AudioActivityTrackerTest, test_noActivityUpdate) {
|
|||
.WillOnce(InvokeWithoutArgs(this, &AudioActivityTrackerTest::wakeOnSetState));
|
||||
|
||||
m_audioActivityTracker->provideState(NAMESPACE_AND_NAME_STATE, PROVIDE_STATE_TOKEN_TEST);
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
|
||||
}
|
||||
|
||||
/// Test if there's an empty set of activity updates, AudioActivityTracker will return an empty context.
|
||||
|
@ -238,13 +243,13 @@ TEST_F(AudioActivityTrackerTest, test_emptyActivityUpdate) {
|
|||
|
||||
m_audioActivityTracker->notifyOfActivityUpdates(channels);
|
||||
m_audioActivityTracker->provideState(NAMESPACE_AND_NAME_STATE, PROVIDE_STATE_TOKEN_TEST);
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
|
||||
}
|
||||
|
||||
/// Test if there's an activityUpdate for one active channel, context will be reported correctly.
|
||||
TEST_F(AudioActivityTrackerTest, test_oneActiveChannel) {
|
||||
std::vector<Channel::State> channels;
|
||||
m_dialogChannel->setFocus(FocusState::FOREGROUND);
|
||||
m_dialogChannel->setFocus(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
channels.push_back(m_dialogChannel->getState());
|
||||
provideUpdate(channels);
|
||||
}
|
||||
|
@ -255,8 +260,11 @@ TEST_F(AudioActivityTrackerTest, test_oneActiveChannel) {
|
|||
*/
|
||||
TEST_F(AudioActivityTrackerTest, test_oneActiveChannelWithAIPAsInterface) {
|
||||
std::vector<Channel::State> channels;
|
||||
m_dialogChannel->setInterface(AIP_INTERFACE_NAME);
|
||||
m_dialogChannel->setFocus(FocusState::FOREGROUND);
|
||||
auto mockObserver = std::make_shared<MockChannelObserver>();
|
||||
auto aipActivity =
|
||||
avsCommon::sdkInterfaces::FocusManagerInterface::Activity::create(AIP_INTERFACE_NAME, mockObserver);
|
||||
m_dialogChannel->setPrimaryActivity(aipActivity);
|
||||
m_dialogChannel->setFocus(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
channels.push_back(m_dialogChannel->getState());
|
||||
EXPECT_CALL(
|
||||
*(m_mockContextManager.get()),
|
||||
|
@ -267,7 +275,7 @@ TEST_F(AudioActivityTrackerTest, test_oneActiveChannelWithAIPAsInterface) {
|
|||
m_audioActivityTracker->notifyOfActivityUpdates(channels);
|
||||
std::this_thread::sleep_for(SHORT_TIMEOUT_MS);
|
||||
m_audioActivityTracker->provideState(NAMESPACE_AND_NAME_STATE, PROVIDE_STATE_TOKEN_TEST);
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -277,7 +285,7 @@ TEST_F(AudioActivityTrackerTest, test_oneActiveChannelWithAIPAsInterface) {
|
|||
*/
|
||||
TEST_F(AudioActivityTrackerTest, test_oneActiveChannelWithDefaultAndAIPAsInterfaces) {
|
||||
std::vector<Channel::State> channels;
|
||||
m_dialogChannel->setFocus(FocusState::FOREGROUND);
|
||||
m_dialogChannel->setFocus(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
channels.push_back(m_dialogChannel->getState());
|
||||
provideUpdate(channels);
|
||||
}
|
||||
|
@ -285,8 +293,8 @@ TEST_F(AudioActivityTrackerTest, test_oneActiveChannelWithDefaultAndAIPAsInterfa
|
|||
/// Test if there's an activityUpdate for two active channels, context will be reported correctly.
|
||||
TEST_F(AudioActivityTrackerTest, test_twoActiveChannels) {
|
||||
std::vector<Channel::State> channels;
|
||||
m_dialogChannel->setFocus(FocusState::FOREGROUND);
|
||||
m_contentChannel->setFocus(FocusState::BACKGROUND);
|
||||
m_dialogChannel->setFocus(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
m_contentChannel->setFocus(FocusState::BACKGROUND, MixingBehavior::MUST_PAUSE);
|
||||
channels.push_back(m_dialogChannel->getState());
|
||||
channels.push_back(m_contentChannel->getState());
|
||||
provideUpdate(channels);
|
||||
|
@ -295,10 +303,10 @@ TEST_F(AudioActivityTrackerTest, test_twoActiveChannels) {
|
|||
/// Test if there's an activityUpdate for one active and one idle channels, context will be reported correctly.
|
||||
TEST_F(AudioActivityTrackerTest, test_oneActiveOneIdleChannels) {
|
||||
std::vector<Channel::State> channels;
|
||||
m_dialogChannel->setFocus(FocusState::FOREGROUND);
|
||||
m_contentChannel->setFocus(FocusState::BACKGROUND);
|
||||
m_dialogChannel->setFocus(FocusState::NONE);
|
||||
m_contentChannel->setFocus(FocusState::FOREGROUND);
|
||||
m_dialogChannel->setFocus(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
m_contentChannel->setFocus(FocusState::BACKGROUND, MixingBehavior::MUST_PAUSE);
|
||||
m_dialogChannel->setFocus(FocusState::NONE, MixingBehavior::MUST_STOP);
|
||||
m_contentChannel->setFocus(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
channels.push_back(m_dialogChannel->getState());
|
||||
channels.push_back(m_contentChannel->getState());
|
||||
provideUpdate(channels);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -44,7 +44,7 @@ using namespace avsCommon::utils::json;
|
|||
using namespace ::testing;
|
||||
|
||||
/// Plenty of time for a test to complete.
|
||||
static std::chrono::milliseconds WAIT_TIMEOUT(1000);
|
||||
static std::chrono::milliseconds MY_WAIT_TIMEOUT(1000);
|
||||
|
||||
/// Namespace for AudioActivityTracke.
|
||||
static const std::string NAMESPACE_AUDIO_ACTIVITY_TRACKER("VisualActivityTracker");
|
||||
|
@ -133,7 +133,6 @@ void VisualActivityTrackerTest::SetUp() {
|
|||
ASSERT_TRUE(m_mockContextManager != nullptr);
|
||||
|
||||
m_visualChannel = std::make_shared<Channel>(VISUAL_CHANNEL_NAME, VISUAL_CHANNEL_PRIORITY);
|
||||
m_visualChannel->setInterface(VISUAL_INTERFACE_NAME);
|
||||
ASSERT_TRUE(m_visualChannel != nullptr);
|
||||
}
|
||||
|
||||
|
@ -197,7 +196,7 @@ void VisualActivityTrackerTest::provideUpdate(const std::vector<Channel::State>&
|
|||
m_VisualActivityTracker->notifyOfActivityUpdates(channels);
|
||||
std::this_thread::sleep_for(SHORT_TIMEOUT_MS);
|
||||
m_VisualActivityTracker->provideState(NAMESPACE_AND_NAME_STATE, PROVIDE_STATE_TOKEN_TEST);
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
|
||||
}
|
||||
|
||||
SetStateResult VisualActivityTrackerTest::wakeOnSetState() {
|
||||
|
@ -214,7 +213,7 @@ TEST_F(VisualActivityTrackerTest, test_noActivityUpdate) {
|
|||
.WillOnce(InvokeWithoutArgs(this, &VisualActivityTrackerTest::wakeOnSetState));
|
||||
|
||||
m_VisualActivityTracker->provideState(NAMESPACE_AND_NAME_STATE, PROVIDE_STATE_TOKEN_TEST);
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
||||
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
|
||||
}
|
||||
|
||||
/// Test if there's an empty vector of activity updates, VisualActivityTracker will return an empty context.
|
||||
|
@ -226,7 +225,7 @@ TEST_F(VisualActivityTrackerTest, test_emptyActivityUpdate) {
|
|||
/// Test if there's an activityUpdate for one idle channel, VisualActivityTracker will return an empty context.
|
||||
TEST_F(VisualActivityTrackerTest, test_oneIdleChannel) {
|
||||
std::vector<Channel::State> channels;
|
||||
m_visualChannel->setFocus(FocusState::NONE);
|
||||
m_visualChannel->setFocus(FocusState::NONE, MixingBehavior::MUST_STOP);
|
||||
channels.push_back(m_visualChannel->getState());
|
||||
provideUpdate(channels);
|
||||
}
|
||||
|
@ -234,7 +233,7 @@ TEST_F(VisualActivityTrackerTest, test_oneIdleChannel) {
|
|||
/// Test if there's an activityUpdate for one active channel, context will be reported correctly.
|
||||
TEST_F(VisualActivityTrackerTest, test_oneActiveChannel) {
|
||||
std::vector<Channel::State> channels;
|
||||
m_visualChannel->setFocus(FocusState::FOREGROUND);
|
||||
m_visualChannel->setFocus(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
channels.push_back(m_visualChannel->getState());
|
||||
provideUpdate(channels);
|
||||
}
|
||||
|
@ -246,7 +245,7 @@ TEST_F(VisualActivityTrackerTest, test_oneActiveChannel) {
|
|||
TEST_F(VisualActivityTrackerTest, test_invalidChannelActivityUpdate) {
|
||||
std::vector<Channel::State> channels;
|
||||
auto invalidChannel = std::make_shared<Channel>(INVALID_CHANNEL_NAME, INVALID_CHANNEL_PRIORITY);
|
||||
m_visualChannel->setFocus(FocusState::FOREGROUND);
|
||||
m_visualChannel->setFocus(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
channels.push_back(m_visualChannel->getState());
|
||||
channels.push_back(invalidChannel->getState());
|
||||
provideUpdate(channels);
|
||||
|
@ -258,9 +257,9 @@ TEST_F(VisualActivityTrackerTest, test_invalidChannelActivityUpdate) {
|
|||
*/
|
||||
TEST_F(VisualActivityTrackerTest, test_validChannelTwoActivityUpdates) {
|
||||
std::vector<Channel::State> channels;
|
||||
m_visualChannel->setFocus(FocusState::FOREGROUND);
|
||||
m_visualChannel->setFocus(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
|
||||
channels.push_back(m_visualChannel->getState());
|
||||
m_visualChannel->setFocus(FocusState::BACKGROUND);
|
||||
m_visualChannel->setFocus(FocusState::BACKGROUND, MixingBehavior::MUST_PAUSE);
|
||||
channels.push_back(m_visualChannel->getState());
|
||||
provideUpdate(channels);
|
||||
}
|
||||
|
|
|
@ -111,6 +111,11 @@ public:
|
|||
*/
|
||||
std::string getUnparsedDirective() const;
|
||||
|
||||
/**
|
||||
* Returns the attachmentContextId.
|
||||
*/
|
||||
std::string getAttachmentContextId() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Constructor.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -31,7 +31,7 @@ namespace avs {
|
|||
* The structure representing the endpoint attributes used for discovery.
|
||||
*
|
||||
* This structure mirrors the AVS definition which is documented here:
|
||||
* https://developer.amazon.com/docs/alexa-voice-service/alexa-discovery.html
|
||||
* https://developer.amazon.com/docs/alexa/alexa-voice-service/alexa-discovery.html
|
||||
*
|
||||
* @note The following attributes will differ from the default endpoint, used to describe this Alexa client, to any
|
||||
* other endpoint controlled by this client. The differences are:
|
||||
|
@ -85,7 +85,7 @@ struct AVSDiscoveryEndpointAttributes {
|
|||
|
||||
/// Maximum length of each endpoint attribute:
|
||||
/// See format specification here:
|
||||
/// https://developer.amazon.com/docs/alexa-voice-service/alexa-discovery.html#addorupdatereport
|
||||
/// https://developer.amazon.com/docs/alexa/alexa-voice-service/alexa-discovery.html#addorupdatereport
|
||||
/// @{
|
||||
static constexpr size_t MAX_ENDPOINT_IDENTIFIER_LENGTH = 256;
|
||||
static constexpr size_t MAX_FRIENDLY_NAME_LENGTH = 128;
|
||||
|
@ -112,7 +112,7 @@ struct AVSDiscoveryEndpointAttributes {
|
|||
std::string manufacturerName;
|
||||
|
||||
/// The display categories the device belongs to. This field should contain at least one category. See categories
|
||||
/// in this document: https://developer.amazon.com/docs/device-apis/alexa-discovery.html#display-categories
|
||||
/// in this document: https://developer.amazon.com/docs/alexa/device-apis/alexa-discovery.html#display-categories
|
||||
/// @note: This value should only include ALEXA_VOICE_ENABLED for the default endpoint.
|
||||
std::vector<std::string> displayCategories;
|
||||
|
||||
|
@ -124,7 +124,7 @@ struct AVSDiscoveryEndpointAttributes {
|
|||
|
||||
/// The optional connections list describing how the endpoint is connected to the internet or smart home hub.
|
||||
/// You can find the values available here:
|
||||
/// https://developer.amazon.com/docs/alexa-voice-service/alexa-discovery.html#addorupdatereport
|
||||
/// https://developer.amazon.com/docs/alexa/alexa-voice-service/alexa-discovery.html#addorupdatereport
|
||||
std::vector<std::map<std::string, std::string>> connections;
|
||||
|
||||
/// The optional custom key value pair used to store about the device. In the AVS documentation, this field name is
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -27,7 +27,7 @@ namespace avs {
|
|||
/**
|
||||
* The structure representing the endpoint attributes that may be included in AVS Directives and Events.
|
||||
*
|
||||
* See https://developer.amazon.com/docs/alexa-voice-service/versioning.html for more details.
|
||||
* See https://developer.amazon.com/docs/alexa/alexa-voice-service/versioning.html for more details.
|
||||
*/
|
||||
struct AVSMessageEndpoint {
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -28,7 +28,7 @@ using AlexaAssetId = std::string;
|
|||
|
||||
/**
|
||||
* String constants for the asset identifier.
|
||||
* @see https://developer.amazon.com/docs/device-apis/resources-and-assets.html#global-alexa-catalog
|
||||
* @see https://developer.amazon.com/docs/alexa/device-apis/resources-and-assets.html#global-alexa-catalog
|
||||
*/
|
||||
|
||||
/// Asset identifier for device with friendly name "Shower".
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -25,7 +25,7 @@ namespace avs {
|
|||
|
||||
/**
|
||||
* An enum class indicating possible response from the endpoint on a controller API call.
|
||||
* Response are derived from @see https://developer.amazon.com/docs/device-apis/alexa-errorresponse.html
|
||||
* Response are derived from @see https://developer.amazon.com/docs/alexa/device-apis/alexa-errorresponse.html
|
||||
*/
|
||||
enum class AlexaResponseType {
|
||||
/// Success
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -28,7 +28,7 @@ using AlexaUnitOfMeasure = std::string;
|
|||
|
||||
/**
|
||||
* String constants for the unit of measure.
|
||||
* @see https://developer.amazon.com/docs/device-apis/alexa-property-schemas.html#units-of-measure
|
||||
* @see https://developer.amazon.com/docs/alexa/device-apis/alexa-property-schemas.html#units-of-measure
|
||||
*/
|
||||
|
||||
/// The Alexa unit of measure as angle degrees.
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_ATTACHMENT_DEFAULTATTACHMENTREADER_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_ATTACHMENT_DEFAULTATTACHMENTREADER_H_
|
||||
|
||||
#include <AVSCommon/Utils/Logger/Logger.h>
|
||||
#include <AVSCommon/Utils/Logger/LogEntry.h>
|
||||
#include "AttachmentReader.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
namespace avs {
|
||||
namespace attachment {
|
||||
|
||||
/**
|
||||
* A class that provides functionality to read data from an @c Attachment.
|
||||
*
|
||||
* @note This class is not thread-safe beyond the thread-safety provided by the underlying SharedDataStream object.
|
||||
*/
|
||||
template <typename SDSType>
|
||||
class DefaultAttachmentReader : public AttachmentReader {
|
||||
public:
|
||||
/**
|
||||
* Create an AttachmentReader.
|
||||
*
|
||||
* @param policy The policy this reader should adhere to.
|
||||
* @param sds The underlying @c SharedDataStream which this object will use.
|
||||
* @param offset If being constructed from an existing @c SharedDataStream, the index indicates where to read from.
|
||||
* This parameter defaults to 0, indicating no offset from the specified reference.
|
||||
* @param reference The position in the stream @c offset is applied to. This parameter defaults to @c ABSOLUTE,
|
||||
* indicating offset is relative to the very beginning of the Attachment.
|
||||
* @param resetOnOverrun If overrun is detected on @c read, whether to close the attachment (default behavior) or
|
||||
* to reset the read position to where current write position is (and skip all the bytes in between).
|
||||
* @return Returns a new AttachmentReader, or nullptr if the operation failed.
|
||||
*/
|
||||
static std::unique_ptr<AttachmentReader> create(
|
||||
typename SDSType::Reader::Policy policy,
|
||||
std::shared_ptr<SDSType> sds,
|
||||
typename SDSType::Index offset = 0,
|
||||
typename SDSType::Reader::Reference reference = SDSType::Reader::Reference::ABSOLUTE,
|
||||
bool resetOnOverrun = false);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~DefaultAttachmentReader();
|
||||
|
||||
/// @name AttachmentReader methods.
|
||||
/// @{
|
||||
std::size_t read(
|
||||
void* buf,
|
||||
std::size_t numBytes,
|
||||
ReadStatus* readStatus,
|
||||
std::chrono::milliseconds timeoutMs = std::chrono::milliseconds(0)) override;
|
||||
|
||||
void close(ClosePoint closePoint = ClosePoint::AFTER_DRAINING_CURRENT_BUFFER) override;
|
||||
|
||||
bool seek(uint64_t offset) override;
|
||||
|
||||
uint64_t getNumUnreadBytes() override;
|
||||
|
||||
/// @}
|
||||
private:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param policy The @c ReaderPolicy of this object.
|
||||
* @param sds The underlying @c SharedDataStream which this object will use.
|
||||
* @param resetOnOverrun If overrun is detected on @c read, whether to close the attachment (default behavior) or
|
||||
* to reset the read position to where current write position is (and skip all the bytes in between).
|
||||
*/
|
||||
DefaultAttachmentReader(typename SDSType::Reader::Policy policy, std::shared_ptr<SDSType> sds, bool resetOnOverrun);
|
||||
|
||||
/// Log tag
|
||||
static const std::string TAG;
|
||||
|
||||
/// The underlying @c SharedDataStream reader.
|
||||
std::shared_ptr<typename SDSType::Reader> m_reader;
|
||||
|
||||
// On @c read overrun, Whether to close the attachment, or reset it to catch up with the write
|
||||
bool m_resetOnOverrun;
|
||||
};
|
||||
|
||||
template <typename SDSType>
|
||||
const std::string DefaultAttachmentReader<SDSType>::TAG = "DefaultAttachmentReader";
|
||||
|
||||
template <typename SDSType>
|
||||
std::unique_ptr<AttachmentReader> DefaultAttachmentReader<SDSType>::create(
|
||||
typename SDSType::Reader::Policy policy,
|
||||
std::shared_ptr<SDSType> sds,
|
||||
typename SDSType::Index offset,
|
||||
typename SDSType::Reader::Reference reference,
|
||||
bool resetOnOverrun) {
|
||||
auto reader =
|
||||
std::unique_ptr<DefaultAttachmentReader>(new DefaultAttachmentReader<SDSType>(policy, sds, resetOnOverrun));
|
||||
if (!reader->m_reader) {
|
||||
ACSDK_ERROR(utils::logger::LogEntry(TAG, "createFailed").d("reason", "object not fully created"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!reader->m_reader->seek(offset, reference)) {
|
||||
ACSDK_ERROR(utils::logger::LogEntry(TAG, "ConstructorFailed").d("reason", "seek failed"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::unique_ptr<AttachmentReader>(reader.release());
|
||||
}
|
||||
|
||||
template <typename SDSType>
|
||||
DefaultAttachmentReader<SDSType>::~DefaultAttachmentReader() {
|
||||
close();
|
||||
}
|
||||
|
||||
template <typename SDSType>
|
||||
std::size_t DefaultAttachmentReader<SDSType>::read(
|
||||
void* buf,
|
||||
std::size_t numBytes,
|
||||
AttachmentReader::ReadStatus* readStatus,
|
||||
std::chrono::milliseconds timeoutMs) {
|
||||
if (!readStatus) {
|
||||
ACSDK_ERROR(utils::logger::LogEntry(TAG, "readFailed").d("reason", "read status is nullptr"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!buf) {
|
||||
ACSDK_ERROR(utils::logger::LogEntry(TAG, "readFailed").d("reason", "buf is nullptr"));
|
||||
*readStatus = ReadStatus::ERROR_INTERNAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_reader) {
|
||||
ACSDK_INFO(utils::logger::LogEntry(TAG, "readFailed").d("reason", "closed or uninitialized SDS"));
|
||||
*readStatus = ReadStatus::CLOSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (timeoutMs.count() < 0) {
|
||||
ACSDK_ERROR(utils::logger::LogEntry(TAG, "readFailed").d("reason", "negative timeout"));
|
||||
*readStatus = ReadStatus::ERROR_INTERNAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*readStatus = ReadStatus::OK;
|
||||
|
||||
if (0 == numBytes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto wordSize = m_reader->getWordSize();
|
||||
if (numBytes < wordSize) {
|
||||
ACSDK_ERROR(
|
||||
utils::logger::LogEntry(TAG, "readFailed").d("reason", "bytes requested smaller than SDS word size"));
|
||||
*readStatus = ReadStatus::ERROR_BYTES_LESS_THAN_WORD_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t bytesRead = 0;
|
||||
const auto numWords = numBytes / wordSize;
|
||||
|
||||
const auto readResult = m_reader->read(buf, numWords, timeoutMs);
|
||||
|
||||
/*
|
||||
* Convert SDS return code accordingly:
|
||||
*
|
||||
* < 0 : Error code.
|
||||
* 0 : The underlying SDS is closed.
|
||||
* > 0 : The number of bytes read.
|
||||
*/
|
||||
|
||||
if (readResult < 0) {
|
||||
switch (readResult) {
|
||||
// This means the writer has overwritten the reader.
|
||||
case SDSType::Reader::Error::OVERRUN:
|
||||
if (m_resetOnOverrun) {
|
||||
// An attachment's read position will be reset to current writer position.
|
||||
// Subsequent reads will deliver data from current writer position onward.
|
||||
*readStatus = ReadStatus::OK_OVERRUN_RESET;
|
||||
ACSDK_DEBUG5(utils::logger::LogEntry(TAG, "readFailed").d("reason", "memory overrun by writer"));
|
||||
m_reader->seek(0, SDSType::Reader::Reference::BEFORE_WRITER);
|
||||
} else {
|
||||
// An attachment cannot recover from this.
|
||||
*readStatus = ReadStatus::ERROR_OVERRUN;
|
||||
ACSDK_ERROR(utils::logger::LogEntry(TAG, "readFailed").d("reason", "memory overrun by writer"));
|
||||
close();
|
||||
}
|
||||
break;
|
||||
|
||||
// This means there is still an active writer, but no data. A read would block if the policy was blocking.
|
||||
case SDSType::Reader::Error::WOULDBLOCK:
|
||||
*readStatus = ReadStatus::OK_WOULDBLOCK;
|
||||
break;
|
||||
|
||||
// This means there is still an active writer, but no data. A read call timed out waiting for data.
|
||||
case SDSType::Reader::Error::TIMEDOUT:
|
||||
*readStatus = ReadStatus::OK_TIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the status was not updated, then there's an error code from SDS we may not be handling.
|
||||
if (ReadStatus::OK == *readStatus) {
|
||||
ACSDK_ERROR(
|
||||
utils::logger::LogEntry(TAG, "readFailed").d("reason", "unhandled error code").d("code", readResult));
|
||||
*readStatus = ReadStatus::ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
} else if (0 == readResult) {
|
||||
*readStatus = ReadStatus::CLOSED;
|
||||
ACSDK_DEBUG0(utils::logger::LogEntry(TAG, "readFailed").d("reason", "SDS is closed"));
|
||||
} else {
|
||||
bytesRead = static_cast<size_t>(readResult) * wordSize;
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
template <typename SDSType>
|
||||
void DefaultAttachmentReader<SDSType>::close(AttachmentReader::ClosePoint closePoint) {
|
||||
if (m_reader) {
|
||||
switch (closePoint) {
|
||||
case ClosePoint::IMMEDIATELY:
|
||||
m_reader->close();
|
||||
return;
|
||||
case ClosePoint::AFTER_DRAINING_CURRENT_BUFFER:
|
||||
m_reader->close(0, SDSType::Reader::Reference::BEFORE_WRITER);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SDSType>
|
||||
bool DefaultAttachmentReader<SDSType>::seek(uint64_t offset) {
|
||||
if (m_reader) {
|
||||
return m_reader->seek(offset);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename SDSType>
|
||||
uint64_t DefaultAttachmentReader<SDSType>::getNumUnreadBytes() {
|
||||
if (m_reader) {
|
||||
return m_reader->tell(SDSType::Reader::Reference::BEFORE_WRITER);
|
||||
}
|
||||
|
||||
ACSDK_ERROR(utils::logger::LogEntry(TAG, "getNumUnreadBytesFailed").d("reason", "noReader"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename SDSType>
|
||||
DefaultAttachmentReader<SDSType>::DefaultAttachmentReader(
|
||||
typename SDSType::Reader::Policy policy,
|
||||
std::shared_ptr<SDSType> sds,
|
||||
bool resetOnOverrun) :
|
||||
m_resetOnOverrun{resetOnOverrun} {
|
||||
if (!sds) {
|
||||
ACSDK_ERROR(utils::logger::LogEntry(TAG, "ConstructorFailed").d("reason", "SDS parameter is nullptr"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_reader = sds->createReader(policy);
|
||||
|
||||
if (!m_reader) {
|
||||
ACSDK_ERROR(utils::logger::LogEntry(TAG, "ConstructorFailed").d("reason", "could not create an SDS reader"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace attachment
|
||||
} // namespace avs
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
#endif // ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_ATTACHMENT_DEFAULTATTACHMENTREADER_H_
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -62,7 +62,7 @@ public:
|
|||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~InProcessAttachmentReader();
|
||||
~InProcessAttachmentReader() = default;
|
||||
|
||||
std::size_t read(
|
||||
void* buf,
|
||||
|
@ -78,20 +78,14 @@ public:
|
|||
|
||||
private:
|
||||
/**
|
||||
* Constructor.
|
||||
* Constructor
|
||||
*
|
||||
* @param policy The @c ReaderPolicy of this object.
|
||||
* @param sds The underlying @c SharedDataStream which this object will use.
|
||||
* @param resetOnOverrun If overrun is detected on @c read, whether to close the attachment (default behavior) or
|
||||
* to reset the read position to where current write position is (and skip all the bytes in between).
|
||||
* @param delegate The reader implementation to use for in process attachment reader.
|
||||
*/
|
||||
InProcessAttachmentReader(SDSTypeReader::Policy policy, std::shared_ptr<SDSType> sds, bool resetOnOverrun);
|
||||
explicit InProcessAttachmentReader(std::unique_ptr<AttachmentReader> delegate);
|
||||
|
||||
/// The underlying @c SharedDataStream reader.
|
||||
std::shared_ptr<SDSTypeReader> m_reader;
|
||||
|
||||
// On @c read overrun, Whether to close the attachment, or reset it to catch up with the write
|
||||
bool m_resetOnOverrun;
|
||||
// Delegate reader
|
||||
std::unique_ptr<AttachmentReader> m_delegate;
|
||||
};
|
||||
|
||||
} // namespace attachment
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -16,14 +16,24 @@
|
|||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_AUDIOINPUTSTREAM_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_AUDIOINPUTSTREAM_H_
|
||||
|
||||
#include "AVSCommon/Utils/SDS/SharedDataStream.h"
|
||||
|
||||
#ifdef CUSTOM_SDS_TRAITS_HEADER
|
||||
#include CUSTOM_SDS_TRAITS_HEADER
|
||||
#else
|
||||
#include "AVSCommon/Utils/SDS/InProcessSDS.h"
|
||||
#endif
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
namespace avs {
|
||||
|
||||
/// The type used store and stream binary data.
|
||||
using AudioInputStream = utils::sds::InProcessSDS;
|
||||
#ifdef CUSTOM_SDS_TRAITS_CLASS
|
||||
using AudioInputStream = utils::sds::SharedDataStream<CUSTOM_SDS_TRAITS_CLASS>;
|
||||
#else
|
||||
using AudioInputStream = utils::sds::SharedDataStream<utils::sds::InProcessSDSTraits>;
|
||||
#endif
|
||||
|
||||
} // namespace avs
|
||||
} // namespace avsCommon
|
||||
|
|
|
@ -74,7 +74,7 @@ public:
|
|||
|
||||
void onDeregistered() override;
|
||||
|
||||
void onFocusChanged(FocusState newFocus) override;
|
||||
void onFocusChanged(FocusState newFocus, MixingBehavior behavior) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -29,7 +29,7 @@ namespace avs {
|
|||
|
||||
/**
|
||||
* This class represents the resources used by a Capability, communicated as friendly names to AVS.
|
||||
* @see https://developer.amazon.com/docs/device-apis/resources-and-assets.html#capability-resources
|
||||
* @see https://developer.amazon.com/docs/alexa/device-apis/resources-and-assets.html#capability-resources
|
||||
*/
|
||||
class CapabilityResources {
|
||||
public:
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_CONTENTTYPE_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_CONTENTTYPE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
namespace avs {
|
||||
|
||||
enum class ContentType {
|
||||
/// Indicates that the corresponding Activity is mixable with other channels
|
||||
/// Such Activities may duck upon receiving FocusState::BACKGROUND focus
|
||||
MIXABLE,
|
||||
|
||||
/// Indicates that the corresponding Activity is not mixable with other channels
|
||||
/// Such Activities must pause upon receiving FocusState::BACKGROUND focus
|
||||
NONMIXABLE,
|
||||
|
||||
/// Indicates that the corresponding ContentType was undefined/unitialized
|
||||
UNDEFINED,
|
||||
|
||||
/// Indicates the Number of @c ContentType enumerations
|
||||
NUM_CONTENT_TYPE
|
||||
};
|
||||
|
||||
/**
|
||||
* This function converts the provided @c ContentType to a string.
|
||||
*
|
||||
* @param contentType The @c ContentType to convert to a string.
|
||||
* @return The string conversion of @c contentType.
|
||||
*/
|
||||
inline std::string contentTypeToString(ContentType contentType) {
|
||||
switch (contentType) {
|
||||
case ContentType::MIXABLE:
|
||||
return "MIXABLE";
|
||||
case ContentType::NONMIXABLE:
|
||||
return "NONMIXABLE";
|
||||
case ContentType::UNDEFINED:
|
||||
return "UNDEFINED";
|
||||
default:
|
||||
return "UNDEFINED";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a @c ContentType value to an @c ostream as a string.
|
||||
*
|
||||
* @param stream The stream to write the value to.
|
||||
* @param contenType The @c ContentType value to write to the @c ostream as a string.
|
||||
* @return The @c ostream that was passed in and written to.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& stream, const ContentType& contentType) {
|
||||
return stream << contentTypeToString(contentType);
|
||||
}
|
||||
} // namespace avs
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
#endif // ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_CONTENTTYPE_H_
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -26,7 +26,7 @@
|
|||
#include "AVSCommon/SDKInterfaces/InteractionModelRequestProcessingObserverInterface.h"
|
||||
#include "AVSCommon/SDKInterfaces/MessageObserverInterface.h"
|
||||
#include "AVSCommon/SDKInterfaces/SpeechSynthesizerObserverInterface.h"
|
||||
|
||||
#include <AVSCommon/Utils/Metrics/MetricRecorderInterface.h>
|
||||
#include <AVSCommon/Utils/Threading/Executor.h>
|
||||
#include <AVSCommon/Utils/Timing/Timer.h>
|
||||
|
||||
|
@ -52,10 +52,12 @@ public:
|
|||
* arrive from AVS.
|
||||
* @param timeoutForListeningToIdle This timeout will be used to time out from the LISTENING state in case the
|
||||
* Request Processing Started (RPS) directive is not received from AVS.
|
||||
* @param metricRecorder The metric recorder.
|
||||
*/
|
||||
DialogUXStateAggregator(
|
||||
std::chrono::milliseconds timeoutForThinkingToIdle = std::chrono::seconds{8},
|
||||
std::chrono::milliseconds timeoutForListeningToIdle = std::chrono::seconds{8});
|
||||
std::chrono::milliseconds timeoutForListeningToIdle = std::chrono::seconds{8},
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> metricRecorder = nullptr);
|
||||
|
||||
/**
|
||||
* Adds an observer to be notified of UX state changes.
|
||||
|
@ -82,7 +84,10 @@ public:
|
|||
|
||||
void onStateChanged(sdkInterfaces::AudioInputProcessorObserverInterface::State state) override;
|
||||
|
||||
void onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState state) override;
|
||||
void onStateChanged(
|
||||
sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState state,
|
||||
const avsCommon::utils::mediaPlayer::MediaPlayerInterface::SourceId mediaSourceId,
|
||||
const avsCommon::utils::Optional<avsCommon::utils::mediaPlayer::MediaPlayerState>& mediaPlayerState) override;
|
||||
|
||||
void receive(const std::string& contextId, const std::string& message) override;
|
||||
|
||||
|
@ -143,6 +148,9 @@ private:
|
|||
*/
|
||||
/// @{
|
||||
|
||||
/// The metric recorder.
|
||||
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> m_metricRecorder;
|
||||
|
||||
/// The @c UXObserverInterface to notify any time the Alexa Voice Service UX state needs to change.
|
||||
std::unordered_set<std::shared_ptr<sdkInterfaces::DialogUXStateObserverInterface>> m_observers;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +16,7 @@
|
|||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_FOCUSSTATE_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_FOCUSSTATE_H_
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -45,7 +45,7 @@ inline int indicatorStateToInt(IndicatorState state) {
|
|||
* @param stateNum The int to convert.
|
||||
* @return The IndicatorState representation of stateNum or nullptr if stateNum is invalid.
|
||||
*/
|
||||
inline const IndicatorState intToIndicatorState(int stateNum) {
|
||||
inline IndicatorState intToIndicatorState(int stateNum) {
|
||||
if (stateNum < 0 || stateNum >= static_cast<int>(IndicatorState::UNDEFINED)) {
|
||||
return IndicatorState::UNDEFINED;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_MIXINGBEHAVIOR_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_MIXINGBEHAVIOR_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
namespace avs {
|
||||
|
||||
enum class MixingBehavior {
|
||||
/// Indicates that the corresponding Activity is the primary Activity on the AFML Channel
|
||||
PRIMARY,
|
||||
|
||||
/// Indicates that the corresponding Activity may duck
|
||||
/// If ducking is not possible, the Activity must pause instead
|
||||
MAY_DUCK,
|
||||
|
||||
/// Indicates that the corresponding Activity must pause
|
||||
MUST_PAUSE,
|
||||
|
||||
/// Indicates that the corresponding Activity must stop
|
||||
MUST_STOP,
|
||||
|
||||
/// Indicates that the corresponding Activity may adopt any one of the above behaviors
|
||||
UNDEFINED
|
||||
};
|
||||
|
||||
/**
|
||||
* This function converts the provided @c MixingBehavior to a string.
|
||||
*
|
||||
* @param behavior The @c MixingBehavior to convert to a string.
|
||||
* @return The string conversion of @c behavior.
|
||||
*/
|
||||
inline std::string mixingBehaviorToString(MixingBehavior behavior) {
|
||||
switch (behavior) {
|
||||
case MixingBehavior::PRIMARY:
|
||||
return "PRIMARY";
|
||||
case MixingBehavior::MAY_DUCK:
|
||||
return "MAY_DUCK";
|
||||
case MixingBehavior::MUST_PAUSE:
|
||||
return "MUST_PAUSE";
|
||||
case MixingBehavior::MUST_STOP:
|
||||
return "MUST_STOP";
|
||||
case MixingBehavior::UNDEFINED:
|
||||
return "UNDEFINED";
|
||||
}
|
||||
return "UNDEFINED";
|
||||
}
|
||||
|
||||
/**
|
||||
* This function reverse maps the provided string to corresponding MixingBehavior Implementation as specified by
|
||||
* mixingBehaviorToString
|
||||
* @param input string to convert to corresponding MixingBehavior
|
||||
* @return @c MixingBehavior that corresponds to the input string. In case of error
|
||||
* the API returns MixingBehavior::UNDEFINED
|
||||
*/
|
||||
inline MixingBehavior getMixingBehavior(const std::string& input) {
|
||||
MixingBehavior behavior = MixingBehavior::UNDEFINED;
|
||||
if (mixingBehaviorToString(MixingBehavior::PRIMARY) == input) {
|
||||
behavior = MixingBehavior::PRIMARY;
|
||||
} else if (mixingBehaviorToString(MixingBehavior::MAY_DUCK) == input) {
|
||||
behavior = MixingBehavior::MAY_DUCK;
|
||||
} else if (mixingBehaviorToString(MixingBehavior::MUST_PAUSE) == input) {
|
||||
behavior = MixingBehavior::MUST_PAUSE;
|
||||
} else if (mixingBehaviorToString(MixingBehavior::MUST_STOP) == input) {
|
||||
behavior = MixingBehavior::MUST_STOP;
|
||||
}
|
||||
|
||||
return behavior;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a @c MixingBehavior value to an @c ostream as a string.
|
||||
*
|
||||
* @param stream The stream to write the value to.
|
||||
* @param behavior The @c MixingBehavior value to write to the @c ostream as a string.
|
||||
* @return The @c ostream that was passed in and written to.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& stream, const MixingBehavior& behavior) {
|
||||
return stream << mixingBehaviorToString(behavior);
|
||||
}
|
||||
|
||||
} // namespace avs
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
#endif // ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_MIXINGBEHAVIOR_H_
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -35,6 +35,10 @@ struct PlayRequestor {
|
|||
std::string id;
|
||||
};
|
||||
|
||||
inline bool operator==(const PlayRequestor& playRequestorA, const PlayRequestor& playRequestorB) {
|
||||
return playRequestorA.type == playRequestorB.type && playRequestorA.id == playRequestorB.id;
|
||||
}
|
||||
|
||||
} // namespace avs
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -23,6 +23,10 @@ namespace avs {
|
|||
/**
|
||||
* An enum class used to specify the refresh policy for the state information provided by a @c stateProviderInterface.
|
||||
* The @c stateProviderInterface must specify the refresh policy when it updates its state via @c setState.
|
||||
*
|
||||
* Note: When a @c stateProviderInterface provides an empty state, the behavior is as follows:
|
||||
* - For @c StateRefreshPolicy @c ALWAYS and @c NEVER, the empty state is included in the context.
|
||||
* - For @c StateRefreshPolicy @c SOMETIMES, the empty state is NOT included in the context.
|
||||
*/
|
||||
enum class StateRefreshPolicy {
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -35,7 +35,7 @@ static const std::string VALUE_KEY_STRING = "value";
|
|||
static const std::string TIME_OF_SAMPLE_KEY_STRING = "timeOfSample";
|
||||
|
||||
/// Key used to identify an the uncertainty in milliseconds related to the time of sample. For more information:
|
||||
/// https://developer.amazon.com/docs/alexa-voice-service/reportable-state-properties.html#property-object
|
||||
/// https://developer.amazon.com/docs/alexa/alexa-voice-service/reportable-state-properties.html#property-object
|
||||
static const std::string UNCERTAINTY_KEY_STRING = "uncertaintyInMilliseconds";
|
||||
|
||||
/// String to identify log entries originating from this file.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -272,9 +272,9 @@ std::pair<std::unique_ptr<AVSDirective>, AVSDirective::ParseStatus> AVSDirective
|
|||
|
||||
std::unique_ptr<AVSDirective> AVSDirective::create(
|
||||
const std::string& unparsedDirective,
|
||||
std::shared_ptr<AVSMessageHeader> avsMessageHeader,
|
||||
const std::shared_ptr<AVSMessageHeader> avsMessageHeader,
|
||||
const std::string& payload,
|
||||
std::shared_ptr<AttachmentManagerInterface> attachmentManager,
|
||||
const std::shared_ptr<AttachmentManagerInterface> attachmentManager,
|
||||
const std::string& attachmentContextId,
|
||||
const utils::Optional<AVSMessageEndpoint>& endpoint) {
|
||||
if (!avsMessageHeader) {
|
||||
|
@ -313,6 +313,10 @@ std::string AVSDirective::getUnparsedDirective() const {
|
|||
return m_unparsedDirective;
|
||||
}
|
||||
|
||||
std::string AVSDirective::getAttachmentContextId() const {
|
||||
return m_attachmentContextId;
|
||||
}
|
||||
|
||||
} // namespace avs
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -13,68 +13,30 @@
|
|||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#include "AVSCommon/AVS/Attachment/DefaultAttachmentReader.h"
|
||||
#include "AVSCommon/AVS/Attachment/InProcessAttachmentReader.h"
|
||||
#include "AVSCommon/Utils/Logger/Logger.h"
|
||||
|
||||
using namespace alexaClientSDK::avsCommon::utils;
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
namespace avs {
|
||||
namespace attachment {
|
||||
|
||||
/// String to identify log entries originating from this file.
|
||||
static const std::string TAG("InProcessAttachmentReader");
|
||||
|
||||
/**
|
||||
* Create a LogEntry using this file's TAG and the specified event string.
|
||||
*
|
||||
* @param The event string for this @c LogEntry.
|
||||
*/
|
||||
#define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event)
|
||||
|
||||
std::unique_ptr<InProcessAttachmentReader> InProcessAttachmentReader::create(
|
||||
SDSTypeReader::Policy policy,
|
||||
std::shared_ptr<SDSType> sds,
|
||||
SDSTypeIndex offset,
|
||||
SDSTypeReader::Reference reference,
|
||||
bool resetOnOverrun) {
|
||||
auto reader =
|
||||
std::unique_ptr<InProcessAttachmentReader>(new InProcessAttachmentReader(policy, sds, resetOnOverrun));
|
||||
|
||||
if (!reader->m_reader) {
|
||||
ACSDK_ERROR(LX("createFailed").d("reason", "object not fully created"));
|
||||
auto readerImpl =
|
||||
DefaultAttachmentReader<SDSType>::create(policy, std::move(sds), offset, reference, resetOnOverrun);
|
||||
if (!readerImpl) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!reader->m_reader->seek(offset, reference)) {
|
||||
ACSDK_ERROR(LX("ConstructorFailed").d("reason", "seek failed"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reader;
|
||||
return std::unique_ptr<InProcessAttachmentReader>(new InProcessAttachmentReader(std::move(readerImpl)));
|
||||
}
|
||||
|
||||
InProcessAttachmentReader::InProcessAttachmentReader(
|
||||
SDSTypeReader::Policy policy,
|
||||
std::shared_ptr<SDSType> sds,
|
||||
bool resetOnOverrun) :
|
||||
m_resetOnOverrun{resetOnOverrun} {
|
||||
if (!sds) {
|
||||
ACSDK_ERROR(LX("ConstructorFailed").d("reason", "SDS parameter is nullptr"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_reader = sds->createReader(policy);
|
||||
|
||||
if (!m_reader) {
|
||||
ACSDK_ERROR(LX("ConstructorFailed").d("reason", "could not create an SDS reader"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
InProcessAttachmentReader::~InProcessAttachmentReader() {
|
||||
close();
|
||||
InProcessAttachmentReader::InProcessAttachmentReader(std::unique_ptr<AttachmentReader> reader) :
|
||||
m_delegate(std::move(reader)) {
|
||||
}
|
||||
|
||||
std::size_t InProcessAttachmentReader::read(
|
||||
|
@ -82,121 +44,19 @@ std::size_t InProcessAttachmentReader::read(
|
|||
std::size_t numBytes,
|
||||
ReadStatus* readStatus,
|
||||
std::chrono::milliseconds timeoutMs) {
|
||||
if (!readStatus) {
|
||||
ACSDK_ERROR(LX("readFailed").d("reason", "read status is nullptr"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_reader) {
|
||||
ACSDK_INFO(LX("readFailed").d("reason", "closed or uninitialized SDS"));
|
||||
*readStatus = ReadStatus::CLOSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (timeoutMs.count() < 0) {
|
||||
ACSDK_ERROR(LX("readFailed").d("reason", "negative timeout"));
|
||||
*readStatus = ReadStatus::ERROR_INTERNAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*readStatus = ReadStatus::OK;
|
||||
|
||||
if (0 == numBytes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto wordSize = m_reader->getWordSize();
|
||||
if (numBytes < wordSize) {
|
||||
ACSDK_ERROR(LX("readFailed").d("reason", "bytes requested smaller than SDS word size"));
|
||||
*readStatus = ReadStatus::ERROR_BYTES_LESS_THAN_WORD_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t bytesRead = 0;
|
||||
auto numWords = numBytes / wordSize;
|
||||
|
||||
auto readResult = m_reader->read(buf, numWords, timeoutMs);
|
||||
|
||||
/*
|
||||
* Convert SDS return code accordingly:
|
||||
*
|
||||
* < 0 : Error code.
|
||||
* 0 : The underlying SDS is closed.
|
||||
* > 0 : The number of bytes read.
|
||||
*/
|
||||
|
||||
if (readResult < 0) {
|
||||
switch (readResult) {
|
||||
// This means the writer has overwritten the reader.
|
||||
case SDSType::Reader::Error::OVERRUN:
|
||||
if (m_resetOnOverrun) {
|
||||
// An attachment's read position will be reset to current writer position.
|
||||
// Subsequent reads will deliver data from current writer position onward.
|
||||
*readStatus = ReadStatus::OK_OVERRUN_RESET;
|
||||
ACSDK_DEBUG5(LX("readFailed").d("reason", "memory overrun by writer"));
|
||||
m_reader->seek(0, SDSTypeReader::Reference::BEFORE_WRITER);
|
||||
} else {
|
||||
// An attachment cannot recover from this.
|
||||
*readStatus = ReadStatus::ERROR_OVERRUN;
|
||||
ACSDK_ERROR(LX("readFailed").d("reason", "memory overrun by writer"));
|
||||
close();
|
||||
}
|
||||
break;
|
||||
|
||||
// This means there is still an active writer, but no data. A read would block if the policy was blocking.
|
||||
case SDSType::Reader::Error::WOULDBLOCK:
|
||||
*readStatus = ReadStatus::OK_WOULDBLOCK;
|
||||
break;
|
||||
|
||||
// This means there is still an active writer, but no data. A read call timed out waiting for data.
|
||||
case SDSType::Reader::Error::TIMEDOUT:
|
||||
*readStatus = ReadStatus::OK_TIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the status was not updated, then there's an error code from SDS we may not be handling.
|
||||
if (ReadStatus::OK == *readStatus) {
|
||||
ACSDK_ERROR(LX("readFailed").d("reason", "unhandled error code").d("code", readResult));
|
||||
*readStatus = ReadStatus::ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
} else if (0 == readResult) {
|
||||
*readStatus = ReadStatus::CLOSED;
|
||||
ACSDK_DEBUG0(LX("readFailed").d("reason", "SDS is closed"));
|
||||
} else {
|
||||
bytesRead = static_cast<size_t>(readResult) * wordSize;
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
return m_delegate->read(buf, numBytes, readStatus, timeoutMs);
|
||||
}
|
||||
|
||||
void InProcessAttachmentReader::close(ClosePoint closePoint) {
|
||||
if (m_reader) {
|
||||
switch (closePoint) {
|
||||
case ClosePoint::IMMEDIATELY:
|
||||
m_reader->close();
|
||||
return;
|
||||
case ClosePoint::AFTER_DRAINING_CURRENT_BUFFER:
|
||||
m_reader->close(0, SDSType::Reader::Reference::BEFORE_WRITER);
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_delegate->close(closePoint);
|
||||
}
|
||||
|
||||
bool InProcessAttachmentReader::seek(uint64_t offset) {
|
||||
if (m_reader) {
|
||||
return m_reader->seek(offset);
|
||||
}
|
||||
return false;
|
||||
return m_delegate->seek(offset);
|
||||
}
|
||||
|
||||
uint64_t InProcessAttachmentReader::getNumUnreadBytes() {
|
||||
if (m_reader) {
|
||||
return m_reader->tell(utils::sds::InProcessSDS::Reader::Reference::BEFORE_WRITER);
|
||||
}
|
||||
|
||||
ACSDK_ERROR(LX("getNumUnreadBytesFailed").d("reason", "noReader"));
|
||||
return 0;
|
||||
return m_delegate->getNumUnreadBytes();
|
||||
}
|
||||
|
||||
} // namespace attachment
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -141,7 +141,7 @@ void CapabilityAgent::removeDirective(const std::string& messageId) {
|
|||
m_directiveInfoMap.erase(messageId);
|
||||
}
|
||||
|
||||
void CapabilityAgent::onFocusChanged(FocusState) {
|
||||
void CapabilityAgent::onFocusChanged(FocusState, MixingBehavior) {
|
||||
// default no-op
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -12,6 +12,8 @@
|
|||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
#include <AVSCommon/Utils/Metrics/DataPointCounterBuilder.h>
|
||||
#include <AVSCommon/Utils/Metrics/MetricEventBuilder.h>
|
||||
|
||||
#include "AVSCommon/AVS/DialogUXStateAggregator.h"
|
||||
|
||||
|
@ -20,6 +22,7 @@ namespace avsCommon {
|
|||
namespace avs {
|
||||
|
||||
using namespace sdkInterfaces;
|
||||
using namespace avsCommon::utils::metrics;
|
||||
|
||||
/// String to identify log entries originating from this file.
|
||||
static const std::string TAG("DialogUXStateAggregator");
|
||||
|
@ -36,9 +39,42 @@ static const std::string TAG("DialogUXStateAggregator");
|
|||
*/
|
||||
static const std::chrono::milliseconds SHORT_TIMEOUT{200};
|
||||
|
||||
/// Custom Metrics prefix used by DialogUXStateAggregator.
|
||||
static const std::string CUSTOM_METRIC_PREFIX = "CUSTOM-";
|
||||
|
||||
/// error metric for Listening timeout expires
|
||||
static const std::string LISTENING_TIMEOUT_EXPIRES = "LISTENING_TIMEOUT_EXPIRES";
|
||||
|
||||
/// error metric for Thinking timeout expires
|
||||
static const std::string THINKING_TIMEOUT_EXPIRES = "THINKING_TIMEOUT_EXPIRES";
|
||||
|
||||
/**
|
||||
* Submits a metric of given event name
|
||||
* @param metricRecorder The @c MetricRecorderInterface which records Metric events
|
||||
* @param eventName The name of the metric event
|
||||
*/
|
||||
static void submitMetric(const std::shared_ptr<MetricRecorderInterface>& metricRecorder, const std::string& eventName) {
|
||||
if (!metricRecorder) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto metricEvent = MetricEventBuilder{}
|
||||
.setActivityName(CUSTOM_METRIC_PREFIX + eventName)
|
||||
.addDataPoint(DataPointCounterBuilder{}.setName(eventName).increment(1).build())
|
||||
.build();
|
||||
|
||||
if (metricEvent == nullptr) {
|
||||
ACSDK_ERROR(LX("Error creating metric."));
|
||||
return;
|
||||
}
|
||||
recordMetric(metricRecorder, metricEvent);
|
||||
}
|
||||
|
||||
DialogUXStateAggregator::DialogUXStateAggregator(
|
||||
std::chrono::milliseconds timeoutForThinkingToIdle,
|
||||
std::chrono::milliseconds timeoutForListeningToIdle) :
|
||||
std::chrono::milliseconds timeoutForListeningToIdle,
|
||||
std::shared_ptr<MetricRecorderInterface> metricRecorder) :
|
||||
m_metricRecorder{metricRecorder},
|
||||
m_currentState{DialogUXStateObserverInterface::DialogUXState::IDLE},
|
||||
m_timeoutForThinkingToIdle{timeoutForThinkingToIdle},
|
||||
m_timeoutForListeningToIdle{timeoutForListeningToIdle},
|
||||
|
@ -96,7 +132,10 @@ void DialogUXStateAggregator::onStateChanged(AudioInputProcessorObserverInterfac
|
|||
});
|
||||
}
|
||||
|
||||
void DialogUXStateAggregator::onStateChanged(SpeechSynthesizerObserverInterface::SpeechSynthesizerState state) {
|
||||
void DialogUXStateAggregator::onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState state,
|
||||
const avsCommon::utils::mediaPlayer::MediaPlayerInterface::SourceId mediaSourceId,
|
||||
const avsCommon::utils::Optional<avsCommon::utils::mediaPlayer::MediaPlayerState>& mediaPlayerState) {
|
||||
m_speechSynthesizerState = state;
|
||||
|
||||
m_executor.submit([this, state]() {
|
||||
|
@ -139,7 +178,7 @@ void DialogUXStateAggregator::receive(const std::string& contextId, const std::s
|
|||
void DialogUXStateAggregator::onConnectionStatusChanged(
|
||||
const ConnectionStatusObserverInterface::Status status,
|
||||
const ConnectionStatusObserverInterface::ChangedReason reason) {
|
||||
m_executor.submit([this, &status]() {
|
||||
m_executor.submit([this, status]() {
|
||||
if (status != avsCommon::sdkInterfaces::ConnectionStatusObserverInterface::Status::CONNECTED) {
|
||||
setState(DialogUXStateObserverInterface::DialogUXState::IDLE);
|
||||
}
|
||||
|
@ -201,6 +240,8 @@ void DialogUXStateAggregator::transitionFromThinkingTimedOut() {
|
|||
if (DialogUXStateObserverInterface::DialogUXState::THINKING == m_currentState) {
|
||||
ACSDK_DEBUG(LX("transitionFromThinkingTimedOut"));
|
||||
setState(DialogUXStateObserverInterface::DialogUXState::IDLE);
|
||||
|
||||
submitMetric(m_metricRecorder, THINKING_TIMEOUT_EXPIRES);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -210,6 +251,8 @@ void DialogUXStateAggregator::transitionFromListeningTimedOut() {
|
|||
if (DialogUXStateObserverInterface::DialogUXState::LISTENING == m_currentState) {
|
||||
ACSDK_DEBUG(LX("transitionFromListeningTimedOut"));
|
||||
setState(DialogUXStateObserverInterface::DialogUXState::IDLE);
|
||||
|
||||
submitMetric(m_metricRecorder, LISTENING_TIMEOUT_EXPIRES);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -116,8 +116,6 @@ void MessageRequest::removeObserver(
|
|||
m_observers.erase(observer);
|
||||
}
|
||||
|
||||
using namespace avsCommon::sdkInterfaces;
|
||||
|
||||
} // namespace avs
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
|
@ -51,8 +52,9 @@ void AttachmentUtilsTest::SetUp() {
|
|||
* Test read until end of buffer
|
||||
*/
|
||||
TEST_F(AttachmentUtilsTest, test_readCompleteBuffer) {
|
||||
char dstBuffer[sampleBuffer.length() + 10];
|
||||
memset(dstBuffer, 0, sampleBuffer.length() + 10);
|
||||
std::vector<char> dstBufferVec(sampleBuffer.length() + 10);
|
||||
std::fill(dstBufferVec.begin(), dstBufferVec.end(), 0);
|
||||
char* dstBuffer = dstBufferVec.data();
|
||||
|
||||
AttachmentReader::ReadStatus status;
|
||||
size_t bytesRead = m_attachmentReader->read(dstBuffer, sampleBuffer.length(), &status);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -34,11 +34,15 @@ std::unique_ptr<InProcessSDS> createSDS(int desiredSize) {
|
|||
}
|
||||
|
||||
std::vector<uint8_t> createTestPattern(int patternSize) {
|
||||
std::vector<uint8_t> vec(patternSize);
|
||||
std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t> engine;
|
||||
std::generate(begin(vec), end(vec), std::ref(engine));
|
||||
std::vector<uint8_t> ret(patternSize);
|
||||
std::vector<uint16_t> vec(patternSize);
|
||||
std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint16_t> engine;
|
||||
|
||||
return vec;
|
||||
std::generate(begin(vec), end(vec), std::ref(engine));
|
||||
for (size_t i = 0; i < vec.size(); i++) {
|
||||
ret[i] = static_cast<uint8_t>(vec[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
|
|
@ -2,5 +2,6 @@ add_subdirectory("Attachment")
|
|||
set(INCLUDE_PATH
|
||||
"${AVSCommon_INCLUDE_DIRS}"
|
||||
"${AVSCommon_SOURCE_DIR}/AVS/test"
|
||||
"${AVSCommon_SOURCE_DIR}/SDKInterfaces/test")
|
||||
"${AVSCommon_SOURCE_DIR}/SDKInterfaces/test"
|
||||
"${MetricRecorder_INCLUDE_DIRS}")
|
||||
discover_unit_tests("${INCLUDE_PATH}" "AVSCommon;AttachmentCommonTestLib")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -23,8 +23,8 @@ namespace alexaClientSDK {
|
|||
namespace avsCommon {
|
||||
namespace test {
|
||||
|
||||
using namespace avsCommon::sdkInterfaces;
|
||||
using namespace avsCommon::avs;
|
||||
using namespace avsCommon::sdkInterfaces;
|
||||
|
||||
/// Long time out for observers to wait for the state change callback (we should not reach this).
|
||||
static const auto DEFAULT_TIMEOUT = std::chrono::seconds(5);
|
||||
|
@ -36,6 +36,9 @@ static const auto SHORT_TIMEOUT = std::chrono::milliseconds(50);
|
|||
// This needs to be longer than the values passed into the DialogUXStateAggregator.
|
||||
static const auto TRANSITION_TIMEOUT = std::chrono::milliseconds(300);
|
||||
|
||||
/// Dummy value for a media player source id
|
||||
static const avsCommon::utils::mediaPlayer::MediaPlayerInterface::SourceId TEST_SOURCE_ID = -1;
|
||||
|
||||
/// A test observer that mocks out the DialogUXStateObserverInterface##onDialogUXStateChanged() call.
|
||||
class TestObserver : public DialogUXStateObserverInterface {
|
||||
public:
|
||||
|
@ -145,6 +148,9 @@ protected:
|
|||
/// Another test observer
|
||||
std::shared_ptr<TestObserver> m_anotherTestObserver;
|
||||
|
||||
/// A MediaPlayerState object passed to onStateChange by SpeechSynthesizer
|
||||
avsCommon::utils::mediaPlayer::MediaPlayerState m_testMediaPlayerState;
|
||||
|
||||
virtual void SetUp() {
|
||||
m_aggregator = std::make_shared<DialogUXStateAggregator>();
|
||||
ASSERT_TRUE(m_aggregator);
|
||||
|
@ -298,7 +304,8 @@ TEST_F(DialogUXAggregatorTest, test_listeningThenReceiveThenSpeakGoesToSpeakButN
|
|||
|
||||
m_aggregator->receive("", "");
|
||||
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::SPEAKING);
|
||||
|
||||
|
@ -316,12 +323,14 @@ TEST_F(DialogUXAggregatorTest, test_speakingAndRecognizingFinishedGoesToIdle) {
|
|||
|
||||
m_aggregator->receive("", "");
|
||||
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::SPEAKING);
|
||||
|
||||
m_aggregator->onStateChanged(AudioInputProcessorObserverInterface::State::IDLE);
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::IDLE);
|
||||
}
|
||||
|
@ -332,20 +341,24 @@ TEST_F(DialogUXAggregatorTest, test_nonIdleObservantsPreventsIdle) {
|
|||
|
||||
// AIP is active, SS is not. Expected: non idle
|
||||
m_aggregator->onStateChanged(AudioInputProcessorObserverInterface::State::BUSY);
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::LISTENING);
|
||||
|
||||
// Both AIP and SS are inactive. Expected: idle
|
||||
m_aggregator->onStateChanged(AudioInputProcessorObserverInterface::State::IDLE);
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::IDLE);
|
||||
|
||||
// AIP is inactive, SS is active. Expected: non-idle
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::SPEAKING);
|
||||
|
||||
// AIP is inactive, SS is inactive: Expected: idle
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::IDLE);
|
||||
}
|
||||
|
||||
|
@ -360,11 +373,13 @@ TEST_F(DialogUXAggregatorTest, test_speakingFinishedDoesNotGoesToIdleImmediately
|
|||
|
||||
m_aggregator->receive("", "");
|
||||
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::SPEAKING);
|
||||
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
|
||||
assertNoStateChange(m_testObserver);
|
||||
}
|
||||
|
@ -377,7 +392,8 @@ TEST_F(DialogUXAggregatorTest, test_simpleReceiveDoesNothing) {
|
|||
|
||||
assertNoStateChange(m_testObserver);
|
||||
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::SPEAKING);
|
||||
|
||||
|
@ -399,7 +415,9 @@ TEST_F(DialogUXAggregatorTest, test_thinkingThenReceiveRemainsInThinkingIfSpeech
|
|||
m_aggregator->receive("", "");
|
||||
|
||||
m_aggregator->onStateChanged(
|
||||
sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::GAINING_FOCUS);
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::GAINING_FOCUS,
|
||||
TEST_SOURCE_ID,
|
||||
m_testMediaPlayerState);
|
||||
|
||||
// Make sure after SpeechSynthesizer reports GAINING_FOCUS, that it would stay in THINKING state
|
||||
m_aggregator->receive("", "");
|
||||
|
@ -422,14 +440,16 @@ TEST_F(DialogUXAggregatorTest, test_validStatesForRPSToThinking) {
|
|||
|
||||
m_aggregator->receive("", "");
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::IDLE);
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::SPEAKING);
|
||||
m_aggregator->onRequestProcessingStarted();
|
||||
assertNoStateChange(m_testObserver);
|
||||
|
||||
// Reset to IDLE
|
||||
m_aggregator->onStateChanged(AudioInputProcessorObserverInterface::State::IDLE);
|
||||
m_aggregator->onStateChanged(sdkInterfaces::SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED);
|
||||
m_aggregator->onStateChanged(
|
||||
SpeechSynthesizerObserverInterface::SpeechSynthesizerState::FINISHED, TEST_SOURCE_ID, m_testMediaPlayerState);
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::IDLE);
|
||||
m_aggregator->onStateChanged(AudioInputProcessorObserverInterface::State::EXPECTING_SPEECH);
|
||||
assertStateChange(m_testObserver, DialogUXStateObserverInterface::DialogUXState::EXPECTING);
|
||||
|
|
|
@ -23,8 +23,8 @@ add_library(AVSCommon SHARED
|
|||
AVS/src/Attachment/InProcessAttachment.cpp
|
||||
AVS/src/Attachment/InProcessAttachmentReader.cpp
|
||||
AVS/src/Attachment/InProcessAttachmentWriter.cpp
|
||||
AVS/src/CapabilityConfiguration.cpp
|
||||
AVS/src/CapabilityAgent.cpp
|
||||
AVS/src/CapabilityConfiguration.cpp
|
||||
AVS/src/CapabilityTag.cpp
|
||||
AVS/src/DialogUXStateAggregator.cpp
|
||||
AVS/src/DirectiveRoutingRule.cpp
|
||||
|
@ -72,14 +72,14 @@ add_library(AVSCommon SHARED
|
|||
Utils/src/Logger/ModuleLogger.cpp
|
||||
Utils/src/Logger/ThreadMoniker.cpp
|
||||
Utils/src/MacAddressString.cpp
|
||||
Utils/src/Metrics/DataPoint.cpp
|
||||
Utils/src/Metrics/DataPointStringBuilder.cpp
|
||||
Utils/src/Metrics/DataPointCounterBuilder.cpp
|
||||
Utils/src/Metrics/DataPointDurationBuilder.cpp
|
||||
Utils/src/Metrics/MetricEvent.cpp
|
||||
Utils/src/Metrics/MetricEventBuilder.cpp
|
||||
Utils/src/MediaPlayer/PooledMediaPlayerFactory.cpp
|
||||
Utils/src/Metrics.cpp
|
||||
Utils/src/Metrics/DataPoint.cpp
|
||||
Utils/src/Metrics/DataPointCounterBuilder.cpp
|
||||
Utils/src/Metrics/DataPointDurationBuilder.cpp
|
||||
Utils/src/Metrics/DataPointStringBuilder.cpp
|
||||
Utils/src/Metrics/MetricEvent.cpp
|
||||
Utils/src/Metrics/MetricEventBuilder.cpp
|
||||
Utils/src/MultiTimer.cpp
|
||||
Utils/src/Network/InternetConnectionMonitor.cpp
|
||||
Utils/src/RequiresShutdown.cpp
|
||||
|
@ -104,6 +104,13 @@ target_include_directories(AVSCommon PUBLIC
|
|||
"${MultipartParser_SOURCE_DIR}"
|
||||
${CURL_INCLUDE_DIRS})
|
||||
|
||||
if (CUSTOM_AUDIO_INPUT_STREAM_TRAITS)
|
||||
target_include_directories(AVSCommon PUBLIC
|
||||
${CUSTOMSDSTRAITS_LIB_DIR}/include)
|
||||
|
||||
target_link_libraries(AVSCommon ${CUSTOMSDSTRAITS_LIB_NAME})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(AVSCommon
|
||||
${CURL_LIBRARIES})
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -20,6 +20,7 @@
|
|||
#include <memory>
|
||||
|
||||
#include <AVSCommon/SDKInterfaces/AVSGatewayAssignerInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/AVSGatewayObserverInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/PostConnectSendMessageInterface.h>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
|
@ -53,6 +54,20 @@ public:
|
|||
* @return True if successful, else false.
|
||||
*/
|
||||
virtual bool setGatewayURL(const std::string& avsGatewayURL) = 0;
|
||||
|
||||
/**
|
||||
* Adds an observer.
|
||||
*
|
||||
* @param observer The @c AVSGatewayObserver
|
||||
*/
|
||||
virtual void addObserver(std::shared_ptr<avsCommon::sdkInterfaces::AVSGatewayObserverInterface> observer) = 0;
|
||||
|
||||
/**
|
||||
* Removes an observer.
|
||||
*
|
||||
* @param observer The @c AVSGatewayObserver.
|
||||
*/
|
||||
virtual void removeObserver(std::shared_ptr<avsCommon::sdkInterfaces::AVSGatewayObserverInterface> observer) = 0;
|
||||
};
|
||||
|
||||
} // namespace sdkInterfaces
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_AVSGATEWAYOBSERVERINTERFACE_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_AVSGATEWAYOBSERVERINTERFACE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
namespace sdkInterfaces {
|
||||
|
||||
/**
|
||||
* An interface for setting AVS gateway.
|
||||
*/
|
||||
class AVSGatewayObserverInterface {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~AVSGatewayObserverInterface() = default;
|
||||
|
||||
/**
|
||||
* Observer method to be called when the AVS Gateway is changed.
|
||||
*
|
||||
* @param avsGateway The AVS Gateway the device should be connected to.
|
||||
*/
|
||||
virtual void onAVSGatewayChanged(const std::string& avsGateway) = 0;
|
||||
};
|
||||
|
||||
} // namespace sdkInterfaces
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
#endif // ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_AVSGATEWAYOBSERVERINTERFACE_H_
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -39,6 +39,14 @@ public:
|
|||
* @param newState New state of the @c EqualizerController.
|
||||
*/
|
||||
virtual void onEqualizerStateChanged(const EqualizerState& newState) = 0;
|
||||
|
||||
/**
|
||||
* Receives the same state of the @c EqualizerController when equalizer setting is changed but to an identical state
|
||||
* to the current state. This callback is called after all changes has been applied.
|
||||
*
|
||||
* @param newState New state of the @c EqualizerController.
|
||||
*/
|
||||
virtual void onEqualizerSameStateChanged(const EqualizerState& newState) = 0;
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +16,7 @@
|
|||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_AUDIOINPUTPROCESSOROBSERVERINTERFACE_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_AUDIOINPUTPROCESSOROBSERVERINTERFACE_H_
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_BLUETOOTHDEVICECONNECTIONRULEINTERFACE_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_BLUETOOTHDEVICECONNECTIONRULEINTERFACE_H_
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <AVSCommon/SDKInterfaces/Bluetooth/BluetoothDeviceInterface.h>
|
||||
#include <AVSCommon/Utils/Bluetooth/DeviceCategory.h>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
namespace sdkInterfaces {
|
||||
namespace bluetooth {
|
||||
|
||||
/**
|
||||
* This interface defines the connection rule the Bluetooth device needs to follow.
|
||||
*/
|
||||
class BluetoothDeviceConnectionRuleInterface {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~BluetoothDeviceConnectionRuleInterface() = default;
|
||||
|
||||
/**
|
||||
* The rule to explicitly connect the Bluetooth device after pair.
|
||||
*
|
||||
* @return true if the caller needs to handle connect logic.
|
||||
*/
|
||||
virtual bool shouldExplicitlyConnect() = 0;
|
||||
|
||||
/**
|
||||
* The rule to explicitly disconnect the Bluetooth device before unpair.
|
||||
*
|
||||
* @return true if the caller needs to handle disconnect logic.
|
||||
*/
|
||||
virtual bool shouldExplicitlyDisconnect() = 0;
|
||||
|
||||
/**
|
||||
* The rule to get a set of Bluetooth devices needed to disconnect when the Bluetooth device connects.
|
||||
*
|
||||
* @param connectedDevices the current connected devices.
|
||||
* @return the set of Bluetooth devices needed to disconnect.
|
||||
*/
|
||||
virtual std::set<std::shared_ptr<BluetoothDeviceInterface>> devicesToDisconnect(
|
||||
std::map<DeviceCategory, std::set<std::shared_ptr<BluetoothDeviceInterface>>> connectedDevices) = 0;
|
||||
|
||||
/**
|
||||
* Get the set of device categories using the connection rule.
|
||||
*
|
||||
* @return The set of @c DeviceCategory of the connection rule.
|
||||
*/
|
||||
virtual std::set<DeviceCategory> getDeviceCategories() = 0;
|
||||
|
||||
/**
|
||||
* Get the set of profile uuids which support those device categories defined in the connection rule.
|
||||
*
|
||||
* @return The set of profile uuids.
|
||||
*/
|
||||
virtual std::set<std::string> getDependentProfiles() = 0;
|
||||
};
|
||||
|
||||
} // namespace bluetooth
|
||||
} // namespace sdkInterfaces
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
#endif // ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_BLUETOOTHDEVICECONNECTIONRULEINTERFACE_H_
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -22,12 +22,10 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/A2DPSourceInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/A2DPSinkInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/AVRCPControllerInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/AVRCPTargetInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/BluetoothServiceInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/SDPRecordInterface.h>
|
||||
#include <AVSCommon/Utils/Bluetooth/MediaStreamingState.h>
|
||||
#include <AVSCommon/Utils/Optional.h>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
|
@ -101,6 +99,41 @@ inline std::ostream& operator<<(std::ostream& stream, const DeviceState state) {
|
|||
/// Represents a Bluetooth Device.
|
||||
class BluetoothDeviceInterface {
|
||||
public:
|
||||
/**
|
||||
* Struct to represent a Bluetooth device meta data.
|
||||
*/
|
||||
struct MetaData {
|
||||
/// The value of undefined class of the Bluetooth device.
|
||||
static const int UNDEFINED_CLASS_VALUE = 0;
|
||||
|
||||
utils::Optional<int> vendorId;
|
||||
utils::Optional<int> productId;
|
||||
int classOfDevice;
|
||||
utils::Optional<int> vendorDeviceSigId;
|
||||
utils::Optional<std::string> vendorDeviceId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param vendorId The vendor id.
|
||||
* @param productId The product id.
|
||||
* @param classOfDevice The class of device.
|
||||
* @param vendorDeviceSigId The vendor device SIG id.
|
||||
* @param vendorDeviceId The vendor device id.
|
||||
*/
|
||||
MetaData(
|
||||
utils::Optional<int> vendorId,
|
||||
utils::Optional<int> productId,
|
||||
int classOfDevice,
|
||||
utils::Optional<int> vendorDeviceSigId,
|
||||
utils::Optional<std::string> vendorDeviceId) :
|
||||
vendorId(vendorId),
|
||||
productId(productId),
|
||||
classOfDevice(classOfDevice),
|
||||
vendorDeviceSigId(vendorDeviceSigId),
|
||||
vendorDeviceId(vendorDeviceId) {
|
||||
}
|
||||
};
|
||||
|
||||
/// Destructor
|
||||
virtual ~BluetoothDeviceInterface() = default;
|
||||
|
||||
|
@ -125,6 +158,13 @@ public:
|
|||
*/
|
||||
virtual DeviceState getDeviceState() = 0;
|
||||
|
||||
/**
|
||||
* Getter for the Bluetooth device metadata.
|
||||
*
|
||||
* @return the meta data of the Bluetooth device.
|
||||
*/
|
||||
virtual MetaData getDeviceMetaData() = 0;
|
||||
|
||||
/**
|
||||
* Getter for the paired state of the device. This should return
|
||||
* the state after any pending state changes have been resolved.
|
||||
|
@ -172,18 +212,27 @@ public:
|
|||
/// @return The Bluetooth Services that this device supports.
|
||||
virtual std::vector<std::shared_ptr<services::SDPRecordInterface>> getSupportedServices() = 0;
|
||||
|
||||
// TODO : Generic getService method.
|
||||
/// @return A pointer to an instance of the @c A2DPSourceInterface if supported, else a nullptr.
|
||||
virtual std::shared_ptr<services::A2DPSourceInterface> getA2DPSource() = 0;
|
||||
/**
|
||||
* Get the Bluetooth service that this device supports.
|
||||
*
|
||||
* @param uuid the uuid of the Bluetooth Service.
|
||||
* @return A pointer to an instance of the @c BluetoothServiceInterface if supported, else a nullptr.
|
||||
*/
|
||||
virtual std::shared_ptr<services::BluetoothServiceInterface> getService(std::string uuid) = 0;
|
||||
|
||||
/// @return A pointer to an instance of the @c A2DPSinkInterface if supported, else a nullptr.
|
||||
virtual std::shared_ptr<services::A2DPSinkInterface> getA2DPSink() = 0;
|
||||
/// @return The current media streaming state of the BluetoothDevice if the device supports A2DP streaming.
|
||||
virtual utils::bluetooth::MediaStreamingState getStreamingState() = 0;
|
||||
|
||||
/// @return A pointer to an instance of the @c AVRCPTargetInterface if supported, else a nullptr.
|
||||
virtual std::shared_ptr<services::AVRCPTargetInterface> getAVRCPTarget() = 0;
|
||||
|
||||
/// @return A pointer to an instance of the @c AVRCPControllerInterface if supported, else a nullptr.
|
||||
virtual std::shared_ptr<services::AVRCPControllerInterface> getAVRCPController() = 0;
|
||||
/**
|
||||
* Toggle the profile of a device, which restricts the future connection/disconnection.
|
||||
*
|
||||
* @param enabled True if need to connect the certain profile, false to disconnect.
|
||||
* @param service The target profile to toggle.
|
||||
* @return A bool indicating success.
|
||||
*/
|
||||
virtual bool toggleServiceConnection(
|
||||
bool enabled,
|
||||
std::shared_ptr<services::BluetoothServiceInterface> service) = 0;
|
||||
};
|
||||
|
||||
} // namespace bluetooth
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -28,8 +28,8 @@ namespace bluetooth {
|
|||
namespace services {
|
||||
|
||||
// TODO: Move to own enum file.
|
||||
/// An Enum representing AVRCP commands.
|
||||
enum class AVRCPCommand {
|
||||
/// An Enum representing Media commands.
|
||||
enum class MediaCommand {
|
||||
/// A Play command.
|
||||
PLAY,
|
||||
|
||||
|
@ -40,38 +40,43 @@ enum class AVRCPCommand {
|
|||
NEXT,
|
||||
|
||||
/// A Previous command. If issued at the beginning of a song, the previous track will be selected.
|
||||
PREVIOUS
|
||||
PREVIOUS,
|
||||
|
||||
/// A Play/Pause command.
|
||||
PLAY_PAUSE
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the @c AVRCPCommand enum to a string.
|
||||
* Converts the @c MediaCommand enum to a string.
|
||||
*
|
||||
* @param cmd The @c AVRCPCommand to convert.
|
||||
* @return A string representation of the @c AVRCPCommand.
|
||||
* @param cmd The @c MediaCommand to convert.
|
||||
* @return A string representation of the @c MediaCommand.
|
||||
*/
|
||||
inline std::string commandToString(AVRCPCommand cmd) {
|
||||
inline std::string commandToString(MediaCommand cmd) {
|
||||
switch (cmd) {
|
||||
case AVRCPCommand::PLAY:
|
||||
case MediaCommand::PLAY:
|
||||
return "PLAY";
|
||||
case AVRCPCommand::PAUSE:
|
||||
case MediaCommand::PAUSE:
|
||||
return "PAUSE";
|
||||
case AVRCPCommand::NEXT:
|
||||
case MediaCommand::NEXT:
|
||||
return "NEXT";
|
||||
case AVRCPCommand::PREVIOUS:
|
||||
case MediaCommand::PREVIOUS:
|
||||
return "PREVIOUS";
|
||||
case MediaCommand::PLAY_PAUSE:
|
||||
return "PLAY_PAUSE";
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload for the @c AVRCPCommand enum. This will write the @c AVRCPCommand as a string to the provided stream.
|
||||
* Overload for the @c MediaCommand enum. This will write the @c MediaCommand as a string to the provided stream.
|
||||
*
|
||||
* @param stream An ostream to send the DeviceState as a string.
|
||||
* @param cmd The @c AVRCPCommand to convert.
|
||||
* @param cmd The @c MediaCommand to convert.
|
||||
* @return The stream.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& stream, const AVRCPCommand cmd) {
|
||||
inline std::ostream& operator<<(std::ostream& stream, const MediaCommand cmd) {
|
||||
return stream << commandToString(cmd);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -26,7 +26,11 @@ namespace sdkInterfaces {
|
|||
namespace bluetooth {
|
||||
namespace services {
|
||||
|
||||
/// Interface representing a BluetoothService.
|
||||
/**
|
||||
* Interface representing a Bluetooth Service.
|
||||
* More Bluetooth Service information(e.g, UUID, NAME) could be found at
|
||||
* https://www.bluetooth.com/specifications/assigned-numbers/service-discovery/
|
||||
*/
|
||||
class BluetoothServiceInterface {
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_SERVICES_HFPINTERFACE_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_SERVICES_HFPINTERFACE_H_
|
||||
|
||||
#include "AVSCommon/SDKInterfaces/Bluetooth/Services/BluetoothServiceInterface.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
namespace sdkInterfaces {
|
||||
namespace bluetooth {
|
||||
namespace services {
|
||||
|
||||
/**
|
||||
* Interface to support hands-free profile.
|
||||
*/
|
||||
class HFPInterface : public BluetoothServiceInterface {
|
||||
public:
|
||||
/// The Service UUID.
|
||||
static constexpr const char* UUID = "0000111e-0000-1000-8000-00805f9b34fb";
|
||||
|
||||
/// The Service Name.
|
||||
static constexpr const char* NAME = "Handsfree";
|
||||
};
|
||||
|
||||
} // namespace services
|
||||
} // namespace bluetooth
|
||||
} // namespace sdkInterfaces
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
#endif // ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_SERVICES_HFPINTERFACE_H_
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_SERVICES_HIDINTERFACE_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_SERVICES_HIDINTERFACE_H_
|
||||
|
||||
#include "AVSCommon/SDKInterfaces/Bluetooth/Services/BluetoothServiceInterface.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
namespace sdkInterfaces {
|
||||
namespace bluetooth {
|
||||
namespace services {
|
||||
|
||||
/**
|
||||
* Interface to support human interface device(such as keyboards, mics) profile.
|
||||
*/
|
||||
class HIDInterface : public BluetoothServiceInterface {
|
||||
public:
|
||||
/// The Service UUID.
|
||||
static constexpr const char* UUID = "00001124-0000-1000-8000-00805f9b34fb";
|
||||
|
||||
/// The Service Name.
|
||||
static constexpr const char* NAME = "HumanInterfaceDeviceService";
|
||||
};
|
||||
|
||||
} // namespace services
|
||||
} // namespace bluetooth
|
||||
} // namespace sdkInterfaces
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
#endif // ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_SERVICES_HIDINTERFACE_H_
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_SERVICES_SPPINTERFACE_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_SERVICES_SPPINTERFACE_H_
|
||||
|
||||
#include "AVSCommon/SDKInterfaces/Bluetooth/Services/BluetoothServiceInterface.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
namespace sdkInterfaces {
|
||||
namespace bluetooth {
|
||||
namespace services {
|
||||
|
||||
/**
|
||||
* Interface to support serial port profile.
|
||||
*/
|
||||
class SPPInterface : public BluetoothServiceInterface {
|
||||
public:
|
||||
/// The Service UUID.
|
||||
static constexpr const char* UUID = "00001101-0000-1000-8000-00805f9b34fb";
|
||||
|
||||
/// The Service Name.
|
||||
static constexpr const char* NAME = "SerialPort";
|
||||
};
|
||||
|
||||
} // namespace services
|
||||
} // namespace bluetooth
|
||||
} // namespace sdkInterfaces
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
||||
#endif // ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_BLUETOOTH_SERVICES_SPPINTERFACE_H_
|
|
@ -100,6 +100,23 @@ public:
|
|||
* Stops the call.
|
||||
*/
|
||||
virtual void stopCall() = 0;
|
||||
|
||||
/**
|
||||
* Mute self during the call.
|
||||
*/
|
||||
virtual void muteSelf() = 0;
|
||||
|
||||
/**
|
||||
* Unmute self during the call.
|
||||
*/
|
||||
virtual void unmuteSelf() = 0;
|
||||
|
||||
/**
|
||||
* Check if the call is muted.
|
||||
*
|
||||
* @return Whether the call is muted.
|
||||
*/
|
||||
virtual bool isSelfMuted() const = 0;
|
||||
};
|
||||
|
||||
inline CallManagerInterface::CallManagerInterface(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -52,6 +52,17 @@ public:
|
|||
* @param state The new CallState.
|
||||
*/
|
||||
virtual void onCallStateChange(CallState state) = 0;
|
||||
|
||||
/**
|
||||
* Checks the state of the provided call state to determine if a call is in an "active" state
|
||||
* Active states are: CONNECTING
|
||||
* INBOUND_RINGING
|
||||
* CALL_CONNETED
|
||||
*
|
||||
* @param state The new CallState.
|
||||
* @return True on states that are considered "active", false otherwise.
|
||||
*/
|
||||
static bool isStateActive(const CallStateObserverInterface::CallState& state);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -82,6 +93,19 @@ inline std::ostream& operator<<(std::ostream& stream, const CallStateObserverInt
|
|||
return stream << "UNKNOWN STATE";
|
||||
}
|
||||
|
||||
inline bool CallStateObserverInterface::isStateActive(const CallStateObserverInterface::CallState& state) {
|
||||
switch (state) {
|
||||
case CallStateObserverInterface::CallState::CONNECTING:
|
||||
case CallStateObserverInterface::CallState::INBOUND_RINGING:
|
||||
case CallStateObserverInterface::CallState::CALL_CONNECTED:
|
||||
return true;
|
||||
case CallStateObserverInterface::CallState::CALL_DISCONNECTED:
|
||||
case CallStateObserverInterface::CallState::NONE:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace sdkInterfaces
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -21,9 +21,10 @@
|
|||
|
||||
#include <AVSCommon/AVS/AVSDiscoveryEndpointAttributes.h>
|
||||
#include <AVSCommon/AVS/CapabilityConfiguration.h>
|
||||
#include <AVSCommon/SDKInterfaces/AlexaEventProcessedObserverInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/AVSGatewayObserverInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/CapabilityConfigurationInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/CapabilitiesObserverInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/AlexaEventProcessedObserverInterface.h>
|
||||
#include <AVSCommon/SDKInterfaces/PostConnectOperationInterface.h>
|
||||
|
||||
namespace alexaClientSDK {
|
||||
|
@ -34,7 +35,9 @@ namespace sdkInterfaces {
|
|||
* CapabilitiesDelegateInterface is an interface with methods that provide clients a way to register endpoints and their
|
||||
* capabilities and publish them so that Alexa is aware of the device's capabilities.
|
||||
*/
|
||||
class CapabilitiesDelegateInterface : public avsCommon::sdkInterfaces::AlexaEventProcessedObserverInterface {
|
||||
class CapabilitiesDelegateInterface
|
||||
: public avsCommon::sdkInterfaces::AlexaEventProcessedObserverInterface
|
||||
, public avsCommon::sdkInterfaces::AVSGatewayObserverInterface {
|
||||
public:
|
||||
/**
|
||||
* Destructor
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -17,6 +17,7 @@
|
|||
#define ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_CHANNELOBSERVERINTERFACE_H_
|
||||
|
||||
#include "AVSCommon/AVS/FocusState.h"
|
||||
#include "AVSCommon/AVS/MixingBehavior.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
|
@ -42,8 +43,11 @@ public:
|
|||
* Channel.
|
||||
*
|
||||
* @param newFocus The new Focus of the channel.
|
||||
* @param behavior The mixingBehavior for the ChannelObserver to take as per the interrupt model
|
||||
* @note when newFocus is FocusState::FOREGROUND, the MixingBehavior shall be guaranteed to be PRIMARY
|
||||
* when newFocus is FocusState::NONE, the MixingBehavior shall be guaranteed to be MUST_STOP
|
||||
*/
|
||||
virtual void onFocusChanged(avs::FocusState newFocus) = 0;
|
||||
virtual void onFocusChanged(avs::FocusState newFocus, avs::MixingBehavior behavior) = 0;
|
||||
};
|
||||
|
||||
} // namespace sdkInterfaces
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -56,7 +56,7 @@ enum class SetStateResult {
|
|||
* Interface to get the context and set the state.
|
||||
* State refers to the client component's state. Context is a container used to communicate the state
|
||||
* of the client components to AVS.
|
||||
* @see https://developer.amazon.com/docs/alexa-voice-service/context.html.
|
||||
* @see https://developer.amazon.com/docs/alexa/alexa-voice-service/context.html.
|
||||
*
|
||||
* @note Implementations must be thread-safe.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -16,12 +16,12 @@
|
|||
#ifndef ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_EXTERNALMEDIAADAPTERINTERFACE_H_
|
||||
#define ALEXA_CLIENT_SDK_AVSCOMMON_SDKINTERFACES_INCLUDE_AVSCOMMON_SDKINTERFACES_EXTERNALMEDIAADAPTERINTERFACE_H_
|
||||
|
||||
#include "AVSCommon/Utils/RequiresShutdown.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "AVSCommon/Utils/RequiresShutdown.h"
|
||||
|
||||
namespace alexaClientSDK {
|
||||
namespace avsCommon {
|
||||
namespace sdkInterfaces {
|
||||
|
@ -139,7 +139,7 @@ enum class SupportedPlaybackOperation {
|
|||
/// Previous
|
||||
PREVIOUS,
|
||||
|
||||
/// Starover a track from the beginning
|
||||
/// Start over a track from the beginning
|
||||
START_OVER,
|
||||
|
||||
/// Fast-forward
|
||||
|
@ -193,7 +193,7 @@ enum class ChangeCauseType {
|
|||
/// Change was triggered by a rule.
|
||||
RULE_TRIGGER,
|
||||
|
||||
/// Change was triggerd by periodic polling.
|
||||
/// Change was triggered by periodic polling.
|
||||
PERIODIC_POLL
|
||||
};
|
||||
|
||||
|
@ -391,9 +391,9 @@ public:
|
|||
/**
|
||||
* ExternalMediaAdapterInterface constructor.
|
||||
*
|
||||
* @param adapaterName The name of the adapter.
|
||||
* @param adapterName The name of the adapter.
|
||||
*/
|
||||
ExternalMediaAdapterInterface(const std::string& adapaterName);
|
||||
explicit ExternalMediaAdapterInterface(const std::string& adapterName);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -34,8 +34,9 @@ struct ObservableSessionProperties {
|
|||
|
||||
/**
|
||||
* Constructor
|
||||
* @param pLoggedIn
|
||||
* @param pUserName
|
||||
*
|
||||
* @param loggedIn Flag that identifies if a users is logged in or not.
|
||||
* @param userName The user name of the currently logged in user.
|
||||
*/
|
||||
ObservableSessionProperties(bool loggedIn, const std::string& userName);
|
||||
|
||||
|
@ -72,8 +73,9 @@ struct ObservablePlaybackStateProperties {
|
|||
|
||||
/**
|
||||
* Constructor
|
||||
* @param pState
|
||||
* @param pTrackName
|
||||
*
|
||||
* @param state The state of the player. State values are "IDLE", "PLAYING", "PAUSED", "STOPPED", "FINISHED".
|
||||
* @param trackName The display name for the playing track.
|
||||
*/
|
||||
ObservablePlaybackStateProperties(const std::string& state, const std::string& trackName);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -18,8 +18,11 @@
|
|||
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <AVSCommon/AVS/ContentType.h>
|
||||
#include "ChannelObserverInterface.h"
|
||||
#include "FocusManagerObserverInterface.h"
|
||||
|
||||
|
@ -34,6 +37,8 @@ namespace sdkInterfaces {
|
|||
*
|
||||
* acquire Channel - clients should call the acquireChannel() method, passing in the name of the Channel they wish to
|
||||
* acquire, a pointer to the observer that they want to be notified once they get focus, and a unique interface name.
|
||||
* clients could alternatively construct an @c Activity object and pass that along with the channel name to acquire the
|
||||
* channel.
|
||||
*
|
||||
* release Channel - clients should call the releaseChannel() method, passing in the name of the Channel and the
|
||||
* observer of the Channel they wish to release.
|
||||
|
@ -48,6 +53,132 @@ namespace sdkInterfaces {
|
|||
*/
|
||||
class FocusManagerInterface {
|
||||
public:
|
||||
/**
|
||||
* An activity representation of an entity that includes details of policy and patience duration that can acquire
|
||||
* a channel.
|
||||
*
|
||||
* If activity A has a patience duration greater than 0, and pushes the current activity B to background,
|
||||
* activity B is eligible to be reinstated as foreground if activity A releases the channel before the duration
|
||||
* of the patience has lapsed.
|
||||
*/
|
||||
class Activity {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new Activity object.
|
||||
*
|
||||
* @param interfaceName The Activity's interface.
|
||||
* @param channelObserver The Activity's Channel Observer.
|
||||
* @param patienceDuration The Activity's Patience Duration.
|
||||
* @param contentType The Activity's Content Type.
|
||||
*/
|
||||
static std::shared_ptr<Activity> create(
|
||||
const std::string& interfaceName,
|
||||
const std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface>& channelObserver,
|
||||
const std::chrono::milliseconds& patienceDuration = std::chrono::milliseconds::zero(),
|
||||
const avsCommon::avs::ContentType contentType = avsCommon::avs::ContentType::NONMIXABLE);
|
||||
|
||||
bool operator==(const Activity& rhs) {
|
||||
return this->m_interface == rhs.m_interface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of Activity's AVS interface.
|
||||
*
|
||||
* @return The name of the AVS interface.
|
||||
*/
|
||||
const std::string getInterface() const;
|
||||
|
||||
/**
|
||||
* Returns the patience duration in milliseconds of Activity. After the release duration, the
|
||||
* backgrounded Activity due to the forgrounding of the Activity with patience will be kicked
|
||||
* out of the stack and will be set to NONE FocusState.
|
||||
*
|
||||
* @return The patience duration in milliseconds of Activity.
|
||||
*/
|
||||
std::chrono::milliseconds getPatienceDuration() const;
|
||||
|
||||
/**
|
||||
* Returns the @c ContentType associated with the @c Activity.
|
||||
*
|
||||
* @return The @c ContentType associated with this @c Activity.
|
||||
*/
|
||||
avsCommon::avs::ContentType getContentType() const;
|
||||
|
||||
/**
|
||||
* Sets the @c ContentType associated with this @c Activity.
|
||||
*
|
||||
* @param contentType The @c ContentType associated with this @c Activity.
|
||||
*/
|
||||
void setContentType(avsCommon::avs::ContentType contentType);
|
||||
|
||||
/**
|
||||
* Gets the last @c MixingBehavior set for this Activity.
|
||||
*
|
||||
* @param The @c MixingBehavior to be set for this @c Activity
|
||||
*/
|
||||
avsCommon::avs::MixingBehavior getMixingBehavior() const;
|
||||
|
||||
/**
|
||||
* Returns the channel observer of Activity.
|
||||
*
|
||||
* @return The channel observer of Activity.
|
||||
*/
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface> getChannelObserver() const;
|
||||
|
||||
/**
|
||||
* Notifies the channel Observer of focus of Channel and Channel owner interface.
|
||||
*
|
||||
* @return @c true if observer was notified, else @c false.
|
||||
*/
|
||||
bool notifyObserver(avs::FocusState focus, avsCommon::avs::MixingBehavior behavior);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Constructs a new Activity object.
|
||||
*
|
||||
* @param interfaceName The Activity's interface.
|
||||
* @param patience The Activity's Patience Duration.
|
||||
* @param channelObserver The Activity's Channel Observer.
|
||||
* @param contentType The Activity's Content Type.
|
||||
*/
|
||||
Activity(
|
||||
const std::string& interfaceName,
|
||||
const std::chrono::milliseconds& patienceDuration,
|
||||
const std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface>& channelObserver,
|
||||
const avsCommon::avs::ContentType contentType) :
|
||||
m_interface{interfaceName},
|
||||
m_patienceDuration{patienceDuration},
|
||||
m_channelObserver{channelObserver},
|
||||
m_contentType{contentType},
|
||||
m_mixingBehavior{avsCommon::avs::MixingBehavior::UNDEFINED} {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the @c MixingBehavior for this @c Activity
|
||||
*
|
||||
* @param behavior The @c MixingBehavior to be set for this @c Activity.
|
||||
*/
|
||||
void setMixingBehavior(avsCommon::avs::MixingBehavior behavior);
|
||||
|
||||
// The mutex that synchronizes all operations within the activity
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
// The interface name of the Activity.
|
||||
const std::string m_interface;
|
||||
|
||||
// The duration of patience in milliseconds of the Activity.
|
||||
const std::chrono::milliseconds m_patienceDuration;
|
||||
|
||||
// The channel observer of the Activity.
|
||||
const std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface> m_channelObserver;
|
||||
|
||||
// The ContentType associated with this Activity
|
||||
avsCommon::avs::ContentType m_contentType;
|
||||
|
||||
// Last MixingBehavior associated with this activity
|
||||
avsCommon::avs::MixingBehavior m_mixingBehavior;
|
||||
};
|
||||
|
||||
/// The default Dialog Channel name.
|
||||
static constexpr const char* DIALOG_CHANNEL_NAME = "Dialog";
|
||||
|
||||
|
@ -84,13 +215,12 @@ public:
|
|||
/**
|
||||
* This method will acquire the channel and grant the appropriate focus to it and other channels if needed. The
|
||||
* caller will be notified via an ChannelObserverInterface##onFocusChanged() call to the @c channelObserver when
|
||||
* it can start the activity. If the Channel was already held by a different observer, the observer will be
|
||||
* notified via ChannelObserverInterface##onFocusChanged() to stop before letting the new observer start.
|
||||
* it can start the activity.
|
||||
*
|
||||
* @param channelName The name of the Channel to acquire.
|
||||
* @param channelObserver The observer that will be acquiring the Channel and be notified of focus changes.
|
||||
* @param interface The name of the AVS interface occupying the Channel. This should be unique and represents the
|
||||
* name of the AVS interface using the Channel. The name of the AVS interface is used by the ActivityTracker to
|
||||
* @param interfaceName The name of the AVS interface occupying the Channel. This should be unique and represents
|
||||
* the name of the AVS interface using the Channel. The name of the AVS interface is used by the ActivityTracker to
|
||||
* send Context to AVS.
|
||||
*
|
||||
* @return Returns @c true if the Channel can be acquired and @c false otherwise.
|
||||
|
@ -98,7 +228,21 @@ public:
|
|||
virtual bool acquireChannel(
|
||||
const std::string& channelName,
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface> channelObserver,
|
||||
const std::string& interface) = 0;
|
||||
const std::string& interfaceName) = 0;
|
||||
|
||||
/**
|
||||
* This method will acquire the channel and grant the appropriate focus to it and other channels if needed. The
|
||||
* caller will be notified via an ChannelObserverInterface##onFocusChanged() call to the @c channelObserver when
|
||||
* it can start the activity.
|
||||
*
|
||||
* @param channelName The name of the Channel to acquire.
|
||||
* @param channelActivity Activity object associated with the Channel.
|
||||
*
|
||||
* @return Returns @c true if the Channel can be acquired and @c false otherwise.
|
||||
*/
|
||||
virtual bool acquireChannel(
|
||||
const std::string& channelName,
|
||||
std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerInterface::Activity> channelActivity) = 0;
|
||||
|
||||
/**
|
||||
* This method will release the Channel and notify the observer of the Channel, if the observer is the same as the
|
||||
|
@ -143,8 +287,88 @@ public:
|
|||
*/
|
||||
virtual void removeObserver(
|
||||
const std::shared_ptr<avsCommon::sdkInterfaces::FocusManagerObserverInterface>& observer) = 0;
|
||||
|
||||
/**
|
||||
* This function allows ChannelObservers to modify the ContentType rendering on their associated Activity
|
||||
* This will cause the focus manager to reconsult the interruptModel in order to determine the new MixingBehavior
|
||||
* for all backgrounded channels.
|
||||
*
|
||||
* @param channelName the channel associated with the ChannelObserver
|
||||
* @param interfaceName the interface name associated with the ChannelObserver
|
||||
* @param contentType the new content type
|
||||
*/
|
||||
virtual void modifyContentType(
|
||||
const std::string& channelName,
|
||||
const std::string& interfaceName,
|
||||
avsCommon::avs::ContentType contentType) = 0;
|
||||
};
|
||||
|
||||
inline std::shared_ptr<FocusManagerInterface::Activity> FocusManagerInterface::Activity::create(
|
||||
const std::string& interfaceName,
|
||||
const std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface>& channelObserver,
|
||||
const std::chrono::milliseconds& patienceDuration,
|
||||
const avsCommon::avs::ContentType contentType) {
|
||||
if (interfaceName.empty() || patienceDuration.count() < 0 || channelObserver == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto activity = std::shared_ptr<FocusManagerInterface::Activity>(
|
||||
new FocusManagerInterface::Activity(interfaceName, patienceDuration, channelObserver, contentType));
|
||||
return activity;
|
||||
}
|
||||
|
||||
inline const std::string FocusManagerInterface::Activity::getInterface() const {
|
||||
return m_interface;
|
||||
}
|
||||
|
||||
inline std::chrono::milliseconds FocusManagerInterface::Activity::getPatienceDuration() const {
|
||||
return m_patienceDuration;
|
||||
}
|
||||
|
||||
inline avsCommon::avs::ContentType FocusManagerInterface::Activity::getContentType() const {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
return m_contentType;
|
||||
}
|
||||
|
||||
inline void FocusManagerInterface::Activity::setContentType(avsCommon::avs::ContentType contentType) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_contentType = contentType;
|
||||
}
|
||||
|
||||
inline avsCommon::avs::MixingBehavior FocusManagerInterface::Activity::getMixingBehavior() const {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return m_mixingBehavior;
|
||||
}
|
||||
|
||||
inline std::shared_ptr<avsCommon::sdkInterfaces::ChannelObserverInterface> FocusManagerInterface::Activity::
|
||||
getChannelObserver() const {
|
||||
return m_channelObserver;
|
||||
}
|
||||
|
||||
inline bool FocusManagerInterface::Activity::notifyObserver(
|
||||
avs::FocusState focus,
|
||||
avsCommon::avs::MixingBehavior behavior) {
|
||||
if (m_channelObserver) {
|
||||
avsCommon::avs::MixingBehavior overrideBehavior{behavior};
|
||||
// If the activity/channelObserver is already paused , do not duck
|
||||
if ((avsCommon::avs::MixingBehavior::MUST_PAUSE == getMixingBehavior()) &&
|
||||
(avsCommon::avs::MixingBehavior::MAY_DUCK == behavior)) {
|
||||
overrideBehavior = avsCommon::avs::MixingBehavior::MUST_PAUSE;
|
||||
}
|
||||
|
||||
m_channelObserver->onFocusChanged(focus, overrideBehavior);
|
||||
// Set the current mixing behavior that the observer received.
|
||||
setMixingBehavior(overrideBehavior);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void FocusManagerInterface::Activity::setMixingBehavior(avsCommon::avs::MixingBehavior behavior) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_mixingBehavior = behavior;
|
||||
}
|
||||
|
||||
} // namespace sdkInterfaces
|
||||
} // namespace avsCommon
|
||||
} // namespace alexaClientSDK
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -74,7 +74,7 @@ public:
|
|||
*
|
||||
* @note The order here means how the modes are organized in the mode controller.
|
||||
* By setting this to @c true, you enable the Alexa to send the @c adjustMode directive.
|
||||
* @see https://developer.amazon.com/docs/alexa-voice-service/alexa-modecontroller.html#capability-assertion
|
||||
* @see https://developer.amazon.com/docs/alexa/alexa-voice-service/alexa-modecontroller.html#capability-assertion
|
||||
*
|
||||
* @note Calling this again will overrite the previous provided value.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -32,7 +32,7 @@ using ModeResources = avsCommon::avs::CapabilityResources;
|
|||
* Struct to hold the Mode Controller attributes required for
|
||||
* Capability Agent discovery.
|
||||
*
|
||||
* @see https://developer.amazon.com/docs/alexa-voice-service/alexa-modecontroller.html#capability-assertion
|
||||
* @see https://developer.amazon.com/docs/alexa/alexa-voice-service/alexa-modecontroller.html#capability-assertion
|
||||
*/
|
||||
struct ModeControllerAttributes {
|
||||
/**
|
||||
|
@ -64,7 +64,11 @@ struct ModeControllerAttributes {
|
|||
const bool ordered;
|
||||
};
|
||||
|
||||
inline ModeControllerAttributes::ModeControllerAttributes() : ordered{false} {
|
||||
inline ModeControllerAttributes::ModeControllerAttributes() :
|
||||
ModeControllerAttributes(
|
||||
avsCommon::avs::CapabilityResources(),
|
||||
std::unordered_map<std::string, ModeResources>(),
|
||||
false) {
|
||||
}
|
||||
|
||||
inline ModeControllerAttributes::ModeControllerAttributes(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2019-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -32,7 +32,7 @@ using PresetResources = avsCommon::avs::CapabilityResources;
|
|||
* Struct to hold the Range Controller attributes required for
|
||||
* Capability Agent discovery.
|
||||
*
|
||||
* @see https://developer.amazon.com/docs/alexa-voice-service/alexa-rangecontroller.html#capability-assertion
|
||||
* @see https://developer.amazon.com/docs/alexa/alexa-voice-service/alexa-rangecontroller.html#capability-assertion
|
||||
*/
|
||||
struct RangeControllerAttributes {
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue