1 /* 2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef VIDEO_BUFFERED_FRAME_DECRYPTOR_H_ 12 #define VIDEO_BUFFERED_FRAME_DECRYPTOR_H_ 13 14 #include <deque> 15 #include <memory> 16 17 #include "api/crypto/crypto_options.h" 18 #include "api/crypto/frame_decryptor_interface.h" 19 #include "api/field_trials_view.h" 20 #include "modules/video_coding/frame_object.h" 21 22 namespace webrtc { 23 24 // This callback is provided during the construction of the 25 // BufferedFrameDecryptor and is called each time a frame is sucessfully 26 // decrypted by the buffer. 27 class OnDecryptedFrameCallback { 28 public: 29 virtual ~OnDecryptedFrameCallback() = default; 30 // Called each time a decrypted frame is returned. 31 virtual void OnDecryptedFrame(std::unique_ptr<RtpFrameObject> frame) = 0; 32 }; 33 34 // This callback is called each time there is a status change in the decryption 35 // stream. For example going from a none state to a first decryption or going 36 // frome a decryptable state to a non decryptable state. 37 class OnDecryptionStatusChangeCallback { 38 public: 39 virtual ~OnDecryptionStatusChangeCallback() = default; 40 // Called each time the decryption stream status changes. This call is 41 // blocking so the caller must relinquish the callback quickly. This status 42 // must match what is specified in the FrameDecryptorInterface file. Notably 43 // 0 must indicate success and any positive integer is a failure. 44 virtual void OnDecryptionStatusChange( 45 FrameDecryptorInterface::Status status) = 0; 46 }; 47 48 // The BufferedFrameDecryptor is responsible for deciding when to pass 49 // decrypted received frames onto the OnDecryptedFrameCallback. Frames can be 50 // delayed when frame encryption is enabled but the key hasn't arrived yet. In 51 // this case we stash about 1 second of encrypted frames instead of dropping 52 // them to prevent re-requesting the key frame. This optimization is 53 // particularly important on low bandwidth networks. Note stashing is only ever 54 // done if we have never sucessfully decrypted a frame before. After the first 55 // successful decryption payloads will never be stashed. 56 class BufferedFrameDecryptor final { 57 public: 58 // Constructs a new BufferedFrameDecryptor that can hold 59 explicit BufferedFrameDecryptor( 60 OnDecryptedFrameCallback* decrypted_frame_callback, 61 OnDecryptionStatusChangeCallback* decryption_status_change_callback, 62 const FieldTrialsView& field_trials); 63 64 ~BufferedFrameDecryptor(); 65 // This object cannot be copied. 66 BufferedFrameDecryptor(const BufferedFrameDecryptor&) = delete; 67 BufferedFrameDecryptor& operator=(const BufferedFrameDecryptor&) = delete; 68 69 // Sets a new frame decryptor as the decryptor for the buffered frame 70 // decryptor. This allows the decryptor to be switched out without resetting 71 // the video stream. 72 void SetFrameDecryptor( 73 rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor); 74 75 // Determines whether the frame should be stashed, dropped or handed off to 76 // the OnDecryptedFrameCallback. 77 void ManageEncryptedFrame(std::unique_ptr<RtpFrameObject> encrypted_frame); 78 79 private: 80 // Represents what should be done with a given frame. 81 enum class FrameDecision { kStash, kDecrypted, kDrop }; 82 83 // Attempts to decrypt the frame, if it fails and no prior frames have been 84 // decrypted it will return kStash. Otherwise fail to decrypts will return 85 // kDrop. Successful decryptions will always return kDecrypted. 86 FrameDecision DecryptFrame(RtpFrameObject* frame); 87 // Retries all the stashed frames this is triggered each time a kDecrypted 88 // event occurs. 89 void RetryStashedFrames(); 90 91 static const size_t kMaxStashedFrames = 24; 92 93 const bool generic_descriptor_auth_experiment_; 94 bool first_frame_decrypted_ = false; 95 FrameDecryptorInterface::Status last_status_ = 96 FrameDecryptorInterface::Status::kUnknown; 97 rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor_; 98 OnDecryptedFrameCallback* const decrypted_frame_callback_; 99 OnDecryptionStatusChangeCallback* const decryption_status_change_callback_; 100 std::deque<std::unique_ptr<RtpFrameObject>> stashed_frames_; 101 }; 102 103 } // namespace webrtc 104 105 #endif // VIDEO_BUFFERED_FRAME_DECRYPTOR_H_ 106