| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CAST_STREAMING_RECEIVER_SESSION_H_ |
| #define CAST_STREAMING_RECEIVER_SESSION_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "cast/common/public/message_port.h" |
| #include "cast/streaming/answer_messages.h" |
| #include "cast/streaming/capture_configs.h" |
| #include "cast/streaming/offer_messages.h" |
| #include "cast/streaming/receiver_packet_router.h" |
| #include "cast/streaming/sender_message.h" |
| #include "cast/streaming/session_config.h" |
| #include "cast/streaming/session_messager.h" |
| #include "util/json/json_serialization.h" |
| |
| namespace openscreen { |
| namespace cast { |
| |
| class Environment; |
| class Receiver; |
| |
| class ReceiverSession final : public Environment::SocketSubscriber { |
| public: |
| // Upon successful negotiation, a set of configured receivers is constructed |
| // for handling audio and video. Note that either receiver may be null. |
| struct ConfiguredReceivers { |
| // In practice, we may have 0, 1, or 2 receivers configured, depending |
| // on if the device supports audio and video, and if we were able to |
| // successfully negotiate a receiver configuration. |
| |
| // NOTES ON LIFETIMES: The audio and video Receiver pointers are owned by |
| // ReceiverSession, not the Client, and references to these pointers must be |
| // cleared before a call to Client::OnReceiversDestroying() returns. |
| |
| // If the receiver is audio- or video-only, or we failed to negotiate |
| // an acceptable session configuration with the sender, then either of the |
| // receivers may be nullptr. In this case, the associated config is default |
| // initialized and should be ignored. |
| Receiver* audio_receiver; |
| AudioCaptureConfig audio_config; |
| |
| Receiver* video_receiver; |
| VideoCaptureConfig video_config; |
| }; |
| |
| // The embedder should provide a client for handling connections. |
| // When a connection is established, the OnMirroringNegotiated callback is |
| // called. |
| class Client { |
| public: |
| enum ReceiversDestroyingReason { kEndOfSession, kRenegotiated }; |
| |
| // Called when a new set of receivers has been negotiated. This may be |
| // called multiple times during a session, as renegotiations occur. |
| virtual void OnMirroringNegotiated(const ReceiverSession* session, |
| ConfiguredReceivers receivers) = 0; |
| |
| // Called immediately preceding the destruction of this session's receivers. |
| // If |reason| is |kEndOfSession|, OnMirroringNegotiated() will never be |
| // called again; if it is |kRenegotiated|, OnMirroringNegotiated() will be |
| // called again soon with a new set of Receivers to use. |
| // |
| // Before returning, the implementation must ensure that all references to |
| // the Receivers, from the last call to OnMirroringNegotiated(), have been |
| // cleared. |
| virtual void OnReceiversDestroying(const ReceiverSession* session, |
| ReceiversDestroyingReason reason) = 0; |
| |
| virtual void OnError(const ReceiverSession* session, Error error) = 0; |
| |
| protected: |
| virtual ~Client(); |
| }; |
| |
| // Note: embedders are required to implement the following |
| // codecs to be Cast V2 compliant: H264, VP8, AAC, Opus. |
| struct Preferences { |
| Preferences(); |
| Preferences(std::vector<VideoCodec> video_codecs, |
| std::vector<AudioCodec> audio_codecs); |
| Preferences(std::vector<VideoCodec> video_codecs, |
| std::vector<AudioCodec> audio_codecs, |
| std::unique_ptr<Constraints> constraints, |
| std::unique_ptr<DisplayDescription> description); |
| |
| Preferences(Preferences&&) noexcept; |
| Preferences(const Preferences&) = delete; |
| Preferences& operator=(Preferences&&) noexcept; |
| Preferences& operator=(const Preferences&) = delete; |
| |
| std::vector<VideoCodec> video_codecs{VideoCodec::kVp8, VideoCodec::kH264}; |
| std::vector<AudioCodec> audio_codecs{AudioCodec::kOpus, AudioCodec::kAac}; |
| |
| // The embedder has the option of directly specifying the display |
| // information and video/audio constraints that will be passed along to |
| // senders during the offer/answer exchange. If nullptr, these are ignored. |
| std::unique_ptr<Constraints> constraints; |
| std::unique_ptr<DisplayDescription> display_description; |
| }; |
| |
| ReceiverSession(Client* const client, |
| Environment* environment, |
| MessagePort* message_port, |
| Preferences preferences); |
| ReceiverSession(const ReceiverSession&) = delete; |
| ReceiverSession(ReceiverSession&&) noexcept = delete; |
| ReceiverSession& operator=(const ReceiverSession&) = delete; |
| ReceiverSession& operator=(ReceiverSession&&) = delete; |
| ~ReceiverSession(); |
| |
| const std::string& session_id() const { return session_id_; } |
| |
| // Environment::SocketSubscriber event callbacks. |
| void OnSocketReady() override; |
| void OnSocketInvalid(Error error) override; |
| |
| private: |
| struct SessionProperties { |
| std::unique_ptr<AudioStream> selected_audio; |
| std::unique_ptr<VideoStream> selected_video; |
| int sequence_number; |
| |
| // To be valid either the audio or video must be selected, and we must |
| // have a sequence number we can reference. |
| bool IsValid() const; |
| }; |
| |
| // Specific message type handler methods. |
| void OnOffer(SenderMessage message); |
| |
| // Creates receivers and sends an appropriate Answer message using the |
| // session properties. |
| void InitializeSession(const SessionProperties& properties); |
| |
| // Used by SpawnReceivers to generate a receiver for a specific stream. |
| std::unique_ptr<Receiver> ConstructReceiver(const Stream& stream); |
| |
| // Creates a set of configured receivers from a given pair of audio and |
| // video streams. NOTE: either audio or video may be null, but not both. |
| ConfiguredReceivers SpawnReceivers(const SessionProperties& properties); |
| |
| // Callers of this method should ensure at least one stream is non-null. |
| Answer ConstructAnswer(const SessionProperties& properties); |
| |
| // Handles resetting receivers and notifying the client. |
| void ResetReceivers(Client::ReceiversDestroyingReason reason); |
| |
| // Sends an error answer reply and notifies the client of the error. |
| void SendErrorAnswerReply(int sequence_number, const char* message); |
| |
| Client* const client_; |
| Environment* const environment_; |
| const Preferences preferences_; |
| // The sender_id of this session. |
| const std::string session_id_; |
| ReceiverSessionMessager messager_; |
| |
| // In some cases, the session initialization may be pending waiting for the |
| // UDP socket to be ready. In this case, the receivers and the answer |
| // message will not be configured and sent until the UDP socket has finished |
| // binding. |
| std::unique_ptr<SessionProperties> pending_session_; |
| |
| bool supports_wifi_status_reporting_ = false; |
| ReceiverPacketRouter packet_router_; |
| |
| std::unique_ptr<Receiver> current_audio_receiver_; |
| std::unique_ptr<Receiver> current_video_receiver_; |
| }; |
| |
| } // namespace cast |
| } // namespace openscreen |
| |
| #endif // CAST_STREAMING_RECEIVER_SESSION_H_ |