diff --git a/video_engine/OWNERS b/video_engine/OWNERS new file mode 100644 index 0000000000..435723d107 --- /dev/null +++ b/video_engine/OWNERS @@ -0,0 +1,4 @@ +mflodman@google.com +perkj@google.com +ronghuawu@google.com +mallinath@google.com diff --git a/video_engine/main/interface/vie_base.h b/video_engine/main/interface/vie_base.h new file mode 100644 index 0000000000..2e6731af9c --- /dev/null +++ b/video_engine/main/interface/vie_base.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This sub-API supports the following functionalities: +// +// - Creating and deleting VideoEngine instances. +// - Creating and deleting channels. +// - Connect a video channel with a corresponding voice channel for audio/video synchronization. +// - Start and stop sending and receiving. + + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_BASE_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_BASE_H_ + +#include "common_types.h" + + +// Forward declarations +namespace webrtc +{ + +class VoiceEngine; + +// ---------------------------------------------------------------------------- +// VideoEngine Callbacks +// ---------------------------------------------------------------------------- + +class WEBRTC_DLLEXPORT ViEBaseObserver +{ +public: + // This method will be called periodically if the average system CPU usage + // exceeds 75%. + virtual void PerformanceAlarm(const unsigned int cpuLoad) = 0; + +protected: + virtual ~ViEBaseObserver() {}; +}; + +// ---------------------------------------------------------------------------- +// VideoEngine +// ---------------------------------------------------------------------------- + +class WEBRTC_DLLEXPORT VideoEngine +{ +public: + // Creates a VideoEngine object, which can then be used to acquire sub‐APIs. + static VideoEngine* Create(); + + // Deletes a VideoEngine instance. + static bool Delete(VideoEngine*& videoEngine); + + // Specifies the amount and type of trace information, which will be created + // by the VideoEngine. + static int SetTraceFilter(const unsigned int filter); + + // Sets the name of the trace file and enables non‐encrypted trace messages. + static int SetTraceFile(const char* fileNameUTF8, + const bool addFileCounter = false); + + // Installs the TraceCallback implementation to ensure that the VideoEngine + // user receives callbacks for generated trace messages. + static int SetTraceCallback(TraceCallback* callback); + + // Android specific + // Provides VideoEngine with pointers to objects supplied by the Java + // applications JNI interface. + static int SetAndroidObjects(void* javaVM, void* javaContext); + +protected: + VideoEngine() {}; + virtual ~VideoEngine() {}; +}; + +// ---------------------------------------------------------------------------- +// VideoBase +// ---------------------------------------------------------------------------- + +class WEBRTC_DLLEXPORT ViEBase +{ +public: + // Factory for the ViEBase sub‐API and increases an internal reference + // counter if successful. Returns NULL if the API is not supported or if + // construction fails. + static ViEBase* GetInterface(VideoEngine* videoEngine); + + // Releases the ViEBase sub-API and decreases an internal reference counter. + // Returns the new reference count. This value should be zero + // for all sub-API:s before the VideoEngine object can be safely deleted. + virtual int Release() = 0; + + // Initiates all common parts of the VideoEngine. + virtual int Init() = 0; + + // Connects a VideoEngine instance to a VoiceEngine instance for audio video + // synchronization. + virtual int SetVoiceEngine(VoiceEngine* ptrVoiceEngine) = 0; + + // Creates a new channel, either with a new encoder instance or by sharing + // encoder instance with an already created channel. + virtual int CreateChannel(int& videoChannel) = 0; + virtual int CreateChannel(int& videoChannel, int originalChannel) = 0; + + // Deletes an existing channel and releases the utilized resources. + virtual int DeleteChannel(const int videoChannel) = 0; + + // Specifies the VoiceEngine and VideoEngine channel pair to use for + // audio/video synchronization. + virtual int ConnectAudioChannel(const int videoChannel, + const int audioChannel) = 0; + + // Disconnects a previously paired VideoEngine and VoiceEngine channel pair. + virtual int DisconnectAudioChannel(const int videoChannel) = 0; + + // Starts sending packets to an already specified IP address and port number + // for a specified channel. + virtual int StartSend(const int videoChannel) = 0; + + // Stops packets from being sent for a specified channel. + virtual int StopSend(const int videoChannel) = 0; + + // Prepares VideoEngine for receiving packets on the specified channel. + virtual int StartReceive(const int videoChannel) = 0; + + // Stops receiving incoming RTP and RTCP packets on the specified channel. + virtual int StopReceive(const int videoChannel) = 0; + + // Registers an instance of a user implementation of the ViEBase + // observer. + virtual int RegisterObserver(ViEBaseObserver& observer) = 0; + + // Removes an already registered instance of ViEBaseObserver. + virtual int DeregisterObserver() = 0; + + // Retrieves the version information for VideoEngine and its components. + virtual int GetVersion(char version[1024]) = 0; + + // Returns the last VideoEngine error code. + virtual int LastError() = 0; + +protected: + ViEBase() {}; + virtual ~ViEBase(){}; +}; + +} // namespace webrtc +#endif // #define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_BASE_H_ diff --git a/video_engine/main/interface/vie_capture.h b/video_engine/main/interface/vie_capture.h new file mode 100644 index 0000000000..7bd71d32cd --- /dev/null +++ b/video_engine/main/interface/vie_capture.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This sub-API supports the following functionalities: +// +// - Allocating capture devices. +// - Connect a capture device with one or more channels. +// - Start and stop capture devices. +// - Getting capture device capabilities. + + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_CAPTURE_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_CAPTURE_H_ + +#include "common_types.h" + +namespace webrtc +{ + +class VideoEngine; +class VideoCaptureModule; + +// This structure describes one set of the supported capabilities for a capture +// device. +struct CaptureCapability +{ + unsigned int width; + unsigned int height; + unsigned int maxFPS; + RawVideoType rawType; + VideoCodecType codecType; + unsigned int expectedCaptureDelay; + bool interlaced; + CaptureCapability() + { + width = 0; + height = 0; + maxFPS = 0; + rawType = kVideoI420; + codecType = kVideoCodecUnknown; + expectedCaptureDelay = 0; + interlaced = false; + } +}; + +// This enumerator tells the current brightness alarm mode. +enum Brightness +{ + Normal = 0, + Bright = 1, + Dark = 2 +}; + +// This enumerator describes the capture alarm mode. +enum CaptureAlarm +{ + AlarmRaised = 0, + AlarmCleared = 1 +}; + +enum RotateCapturedFrame +{ + RotateCapturedFrame_0 = 0, + RotateCapturedFrame_90 = 90, + RotateCapturedFrame_180 = 180, + RotateCapturedFrame_270 = 270 +}; + +// This class declares an abstract interface to be used when using an external +// capture device. The user implemented derived class is registered using +// AllocateExternalCaptureDevice and is released using ReleaseCaptureDevice. +class WEBRTC_DLLEXPORT ViEExternalCapture +{ +public: + ViEExternalCapture() {} + virtual ~ViEExternalCapture() {} + + // This method is called by the user to deliver a new captured frame to + // VideoEngine. + virtual int IncomingFrame(unsigned char* videoFrame, + unsigned int videoFrameLength, + unsigned short width, unsigned short height, + RawVideoType videoType, + unsigned long long captureTime = 0) = 0; +}; + +// ---------------------------------------------------------------------------- +// ViECaptureObserver +// ---------------------------------------------------------------------------- + +// This class declares an abstract interface for a user defined observer. It is +// up to the VideoEngine user to implement a derived class which implements the +// observer class. The observer is registered using RegisterObserver() and +// deregistered using DeregisterObserver(). +class WEBRTC_DLLEXPORT ViECaptureObserver +{ +public: + // This method is called if a bright or dark captured image is detected. + virtual void BrightnessAlarm(const int captureId, + const Brightness brightness) = 0; + + // This method is called periodically telling the capture device frame rate. + virtual void CapturedFrameRate(const int captureId, + const unsigned char frameRate) = 0; + + // This method is called if the capture device stops delivering images to + // VideoEngine. + virtual void NoPictureAlarm(const int captureId, + const CaptureAlarm alarm) = 0; + +protected: + virtual ~ViECaptureObserver() + { + } +}; + +// ---------------------------------------------------------------------------- +// ViECapture +// ---------------------------------------------------------------------------- + +class WEBRTC_DLLEXPORT ViECapture +{ +public: + // Factory for the ViECapture sub‐API and increases an internal reference + // counter if successful. Returns NULL if the API is not supported or if + // construction fails. + static ViECapture* GetInterface(VideoEngine* videoEngine); + + // Releases the ViECapture sub-API and decreases an internal reference + // counter. + // Returns the new reference count. This value should be zero + // for all sub-API:s before the VideoEngine object can be safely deleted. + virtual int Release() = 0; + + + // Gets the number of available capture devices. + virtual int NumberOfCaptureDevices() = 0; + + // Gets the name and unique id of a capture device. + virtual int GetCaptureDevice(unsigned int listNumber, char* deviceNameUTF8, + const unsigned int deviceNameUTF8Length, + char* uniqueIdUTF8, + const unsigned int uniqueIdUTF8Length) = 0; + + // Allocates a capture device to be used in VideoEngine. + virtual int AllocateCaptureDevice(const char* uniqueIdUTF8, + const unsigned int uniqueIdUTF8Length, + int& captureId) = 0; + + // Registers an external capture device to be used in VideoEngine + virtual int AllocateExternalCaptureDevice( + int& captureId, ViEExternalCapture *&externalCapture) = 0; + + // Use capture device using external capture module. + virtual int AllocateCaptureDevice(VideoCaptureModule& captureModule, + int& captureId) = 0; + + // Releases a capture device and makes it available for other applications. + virtual int ReleaseCaptureDevice(const int captureId) = 0; + + // This function connects a capture device with a channel. Multiple channels + // can be connected to the same capture device. + virtual int ConnectCaptureDevice(const int captureId, + const int videoChannel) = 0; + + // Disconnects a capture device as input for a specified channel. + virtual int DisconnectCaptureDevice(const int videoChannel) = 0; + + // Makes a capture device start capturing video frames. + virtual int StartCapture(const int captureId, + const CaptureCapability captureCapability = + CaptureCapability()) = 0; + + // Stops a started capture device from capturing video frames. + virtual int StopCapture(const int captureId) = 0; + + // Rotates captured frames before encoding and sending. + // Used on mobile devices with rotates cameras. + virtual int SetRotateCapturedFrames(const int captureId, + const RotateCapturedFrame rotation) = 0; + + // This function sets the expected delay from when a video frame is captured + // to when that frame is delivered to VideoEngine. + virtual int SetCaptureDelay(const int captureId, + const unsigned int captureDelayMs) = 0; + + // Returns the number of sets of capture capabilities the capture device + // supports. + virtual int NumberOfCapabilities(const char* uniqueIdUTF8, + const unsigned int uniqueIdUTF8Length) = 0; + + // Gets a set of capture capabilities for a specified capture device. + virtual int GetCaptureCapability(const char* uniqueIdUTF8, + const unsigned int uniqueIdUTF8Length, + const unsigned int capabilityNumber, + CaptureCapability& capability) = 0; + + // Displays the capture device property dialog box for the specified capture + // device. Windows only. + virtual int ShowCaptureSettingsDialogBox( + const char* uniqueIdUTF8, const unsigned int uniqueIdUTF8Length, + const char* dialogTitle, void* parentWindow = NULL, + const unsigned int x = 200, const unsigned int y = 200) = 0; + + // Gets the clockwise angle the frames from the camera must be rotated in + // order to display the frames correctly if the display is rotated in its + // natural orientation. + virtual int GetOrientation(const char* uniqueIdUTF8, + RotateCapturedFrame &orientation) = 0; + + // Enables brightness alarm detection and the brightness alarm callback. + virtual int EnableBrightnessAlarm(const int captureId, + const bool enable) = 0; + + // Registers an instance of a user implementation of the ViECaptureObserver. + virtual int RegisterObserver(const int captureId, + ViECaptureObserver& observer) = 0; + + // Removes an already registered instance of ViECaptureObserver. + virtual int DeregisterObserver(const int captureId) = 0; + +protected: + ViECapture() {}; + virtual ~ViECapture() {}; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_CAPTURE_H_ diff --git a/video_engine/main/interface/vie_codec.h b/video_engine/main/interface/vie_codec.h new file mode 100644 index 0000000000..0b2d2aee1f --- /dev/null +++ b/video_engine/main/interface/vie_codec.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This sub-API supports the following functionalities: +// - Setting send and receive codecs. +// - Codec specific settings. +// - Key frame signaling. +// - Stream management settings. + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_CODEC_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_CODEC_H_ + +#include "common_types.h" + +namespace webrtc +{ + +class VideoEngine; +struct VideoCodec; + +// ---------------------------------------------------------------------------- +// ViEEncoderObserver +// ---------------------------------------------------------------------------- + +// This class declares an abstract interface for a user defined observer. It is +// up to the VideoEngine user to implement a derived class which implements the +// observer class. The observer is registered using RegisterEncoderObserver() +// and deregistered using DeregisterEncoderObserver(). +class WEBRTC_DLLEXPORT ViEEncoderObserver +{ +public: + // This method is called once per second with the current encoded frame rate + // and bit rate. + virtual void OutgoingRate(const int videoChannel, + const unsigned int framerate, + const unsigned int bitrate) = 0; +protected: + virtual ~ViEEncoderObserver() {}; +}; + +// ---------------------------------------------------------------------------- +// ViEEncoderObserver +// ---------------------------------------------------------------------------- + +// This class declares an abstract interface for a user defined observer. It is +// up to the VideoEngine user to implement a derived class which implements the +// observer class. The observer is registered using RegisterDecoderObserver() +// and deregistered using DeregisterDecoderObserver(). +class WEBRTC_DLLEXPORT ViEDecoderObserver +{ +public: + // This method is called when a new incoming stream is detected, normally + // triggered by a new incoming SSRC or payload type. + virtual void IncomingCodecChanged(const int videoChannel, + const VideoCodec& videoCodec) = 0; + + // This method is called once per second containing the frame rate and bit + // rate for the incoming stream + virtual void IncomingRate(const int videoChannel, + const unsigned int framerate, + const unsigned int bitrate) = 0; + + // This method is called when the decoder needs a new key frame from encoder + // on the sender. + virtual void RequestNewKeyFrame(const int videoChannel) = 0; + +protected: + virtual ~ViEDecoderObserver() {}; +}; + +// ---------------------------------------------------------------------------- +// ViECodec +// ---------------------------------------------------------------------------- + +class WEBRTC_DLLEXPORT ViECodec +{ +public: + // Factory for the ViECodec sub‐API and increases an internal reference + // counter if successful. Returns NULL if the API is not supported or if + // construction fails. + static ViECodec* GetInterface(VideoEngine* videoEngine); + + // Releases the ViECodec sub-API and decreases an internal reference + // counter. + // Returns the new reference count. This value should be zero + // for all sub-API:s before the VideoEngine object can be safely deleted. + virtual int Release() = 0; + + // Gets the number of available codecs for the VideoEngine build. + virtual int NumberOfCodecs() const = 0; + + // Gets a VideoCodec struct for a codec containing the default configuration + // for that codec type. + virtual int GetCodec(const unsigned char listNumber, + VideoCodec& videoCodec) const = 0; + + // Sets the send codec to use for a specified channel. + virtual int SetSendCodec(const int videoChannel, + const VideoCodec& videoCodec) = 0; + + // Gets the current send codec settings. + virtual int GetSendCodec(const int videoChannel, + VideoCodec& videoCodec) const = 0; + + // Prepares VideoEngine to receive a certain codec type and setting for a + // specified payload type. + virtual int SetReceiveCodec(const int videoChannel, + const VideoCodec& videoCodec) = 0; + + // Gets the current receive codec. + virtual int GetReceiveCodec(const int videoChannel, + VideoCodec& videoCodec) const = 0; + + // This function is used to get codec configuration parameters to be + // signaled from the encoder to the decoder in the call setup. + virtual int GetCodecConfigParameters( + const int videoChannel, + unsigned char configParameters[kConfigParameterSize], + unsigned char& configParametersSize) const = 0; + + // Enables advanced scaling of the captured video stream if the stream + // differs from the send codec settings. + virtual int SetImageScaleStatus(const int videoChannel, + const bool enable) = 0; + + // Gets the number of sent key frames and number of sent delta frames. + virtual int GetSendCodecStastistics(const int videoChannel, + unsigned int& keyFrames, + unsigned int& deltaFrames) const = 0; + + // Gets the number of decoded key frames and number of decoded delta frames. + virtual int GetReceiveCodecStastistics(const int videoChannel, + unsigned int& keyFrames, + unsigned int& deltaFrames) const = 0; + + // Enables key frame request callback in ViEDecoderObserver. + virtual int SetKeyFrameRequestCallbackStatus(const int videoChannel, + const bool enable) = 0; + + // Enables key frame requests for detected lost packets. + virtual int SetSignalKeyPacketLossStatus( + const int videoChannel, const bool enable, + const bool onlyKeyFrames = false) = 0; + + // Registers an instance of a user implementation of the ViEEncoderObserver. + virtual int RegisterEncoderObserver(const int videoChannel, + ViEEncoderObserver& observer) = 0; + + // Removes an already registered instance of ViEEncoderObserver. + virtual int DeregisterEncoderObserver(const int videoChannel) = 0; + + // Registers an instance of a user implementation of the ViEDecoderObserver. + virtual int RegisterDecoderObserver(const int videoChannel, + ViEDecoderObserver& observer) = 0; + + // Removes an already registered instance of ViEDecoderObserver. + virtual int DeregisterDecoderObserver(const int videoChannel) = 0; + + // This function forces the next encoded frame to be a key frame. This is + // normally used when the remote endpoint only supports out‐band key frame + // request. + virtual int SendKeyFrame(const int videoChannel) = 0; + + // This function makes the decoder wait for a key frame before starting to + // decode the incoming video stream. + virtual int WaitForFirstKeyFrame(const int videoChannel, + const bool wait) = 0; + + // This function makes VideoEngine decode all incoming H.263 key frames as + // delta frames and all incoming delta frames as key frames. + virtual int SetInverseH263Logic(int videoChannel, bool enable) = 0; + +protected: + ViECodec() {}; + virtual ~ViECodec() {}; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_CODEC_H_ diff --git a/video_engine/main/interface/vie_encryption.h b/video_engine/main/interface/vie_encryption.h new file mode 100644 index 0000000000..2be59e3b2c --- /dev/null +++ b/video_engine/main/interface/vie_encryption.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This sub-API supports the following functionalities: +// - Secure RTP (SRTP). +// - External encryption and decryption. + + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_ENCRYPTION_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_ENCRYPTION_H_ + +#include "common_types.h" + +namespace webrtc +{ +class VideoEngine; + +// ---------------------------------------------------------------------------- +// ViEEncryption +// ---------------------------------------------------------------------------- + +class WEBRTC_DLLEXPORT ViEEncryption +{ +public: + enum + { + kMaxSrtpKeyLength = 30 + }; + + // Factory for the ViEEncryption sub‐API and increases an internal reference + // counter if successful. Returns NULL if the API is not supported or if + // construction fails. + static ViEEncryption* GetInterface(VideoEngine* videoEngine); + + // Releases the ViEEncryption sub-API and decreases an internal reference + // counter. + // Returns the new reference count. This value should be zero + // for all sub-API:s before the VideoEngine object can be safely deleted. + virtual int Release() = 0; + + // This function enables SRTP on send packets for a specific channel. + virtual int EnableSRTPSend(const int videoChannel, + const CipherTypes cipherType, + const unsigned int cipherKeyLength, + const AuthenticationTypes authType, + const unsigned int authKeyLength, + const unsigned int authTagLength, + const SecurityLevels level, + const unsigned char key[kMaxSrtpKeyLength], + const bool useForRTCP = false) = 0; + + // This function disables SRTP for the specified channel. + virtual int DisableSRTPSend(const int videoChannel) = 0; + + // This function enables SRTP on the received packets for a specific + // channel. + virtual int EnableSRTPReceive(const int videoChannel, + const CipherTypes cipherType, + const unsigned int cipherKeyLength, + const AuthenticationTypes authType, + const unsigned int authKeyLength, + const unsigned int authTagLength, + const SecurityLevels level, + const unsigned char key[kMaxSrtpKeyLength], + const bool useForRTCP = false) = 0; + + // This function disables SRTP on received packets for a specific channel. + virtual int DisableSRTPReceive(const int videoChannel) = 0; + + // This function registers a encryption derived instance and enables + // external encryption for the specified channel. + virtual int RegisterExternalEncryption(const int videoChannel, + Encryption& encryption) = 0; + + // This function deregisters a registered encryption derived instance + // and disables external encryption. + virtual int DeregisterExternalEncryption(const int videoChannel) = 0; + +protected: + ViEEncryption() {}; + virtual ~ViEEncryption() {}; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_ENCRYPTION_H_ diff --git a/video_engine/main/interface/vie_errors.h b/video_engine/main/interface/vie_errors.h new file mode 100644 index 0000000000..78ae5520b9 --- /dev/null +++ b/video_engine/main/interface/vie_errors.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_ERRORS_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_ERRORS_H_ + + +enum ViEErrors { + + //ViEBase + kViENotInitialized = 12000, // Init has not been called successfully. + kViEBaseVoEFailure, // SetVoiceEngine. ViE failed to use VE instance. Check VE instance pointer.ConnectAudioChannel failed to set voice channel. Have SetVoiceEngine been called? Is the voice channel correct. + kViEBaseChannelCreationFailed, // CreateChannel. + kViEBaseInvalidChannelId, // The channel does not exist. + kViEAPIDoesNotExist, // Release called on Interface that has not been created. + kViEBaseInvalidArgument, + kViEBaseAlreadySending, // StartSend called on channel that is already sending. + kViEBaseNotSending, // StopSend called on channel that is not sending. + kViEBaseAlreadyReceiving, // StartReceive called on channel that is already receiving. + kViEBaseObserverAlreadyRegistered, // RegisterObserver- an observer has already been set. + kViEBaseObserverNotRegistered, // DeregisterObserver - no observer has been registered. + kViEBaseUnknownError, // An unknown error has occurred. Check the log file. + + //ViECodec + kViECodecInvalidArgument = 12100, // Wrong input parameter to function. + kViECodecObserverAlreadyRegistered, // RegisterEncoderObserver, RegisterDecoderObserver. + kViECodecObserverNotRegistered, // DeregisterEncoderObserver, DeregisterDecoderObserver. + kViECodecInvalidCodec, // SetSendCodec,SetReceiveCodec- The codec structure is invalid. + kViECodecInvalidChannelId, // The channel does not exist. + kViECodecInUse, // SetSendCodec- Can't change codec size or type when multiple channels use the same encoder. + kViECodecUnknownError, // An unknown error has occurred. Check the log file. + + //ViERender + kViERenderInvalidRenderId = 12200, // No renderer with the ID exist. In AddRenderer - The render ID is invalid. No capture device, channel or file is allocated with that id. + kViERenderAlreadyExists, // AddRenderer: the renderer already exist. + kViERenderInvalidFrameFormat, // AddRender (external renderer). The user has requested a frame format that we don't support. + kViERenderUnknownError, // An unknown error has occurred. Check the log file. + + //ViECapture + kViECaptureDeviceAlreadyConnected = 12300, // ConnectCaptureDevice - A capture device has already been connected to this video channel. + kViECaptureDeviceDoesnNotExist, // No capture device exist with the provided capture id or unique name. + kViECaptureDeviceInvalidChannelId, // ConnectCaptureDevice, DisconnectCaptureDevice- No Channel exist with the provided channel id. + kViECaptureDeviceNotConnected, // DisconnectCaptureDevice- No capture device is connected to the channel. + kViECaptureDeviceNotStarted, // Stop- The capture device is not started. + kViECaptureDeviceAlreadyStarted, // Start- The capture device is already started. + kViECaptureDeviceAlreadyAllocated, // AllocateCaptureDevice The device is already allocated. + kViECaptureDeviceMaxNoDevicesAllocated, // AllocateCaptureDevice Max number of devices already allocated. + kViECaptureObserverAlreadyRegistered, // RegisterObserver- An observer is already registered. Need to deregister first. + kViECaptureDeviceObserverNotRegistered, // DeregisterObserver- No observer is registered. + kViECaptureDeviceUnknownError, // An unknown error has occurred. Check the log file. + kViECaptureDeviceMacQtkitNotSupported, // QTKit handles the capture devices automatically. Thus querying capture capabilities is not supported. + + //ViEFile + kViEFileInvalidChannelId = 12400, // No Channel exist with the provided channel id. + kViEFileInvalidArgument, // Incorrect input argument + kViEFileAlreadyRecording, // StartRecordOutgoingVideo - already recording channel + kViEFileVoENotSet, // StartRecordOutgoingVideo. Failed to access voice engine. Has SetVoiceEngine been called? + kViEFileNotRecording, // StopRecordOutgoingVideo + kViEFileMaxNoOfFilesOpened, // StartPlayFile + kViEFileNotPlaying, // StopPlayFile. The file with the provided id is not playing. + kViEFileObserverAlreadyRegistered, // RegisterObserver + kViEFileObserverNotRegistered, // DeregisterObserver + kViEFileInputAlreadyConnected, // SendFileOnChannel- the video channel already have a connected input. + kViEFileNotConnected, // StopSendFileOnChannel- No file is being sent on the channel. + kViEFileVoEFailure, // SendFileOnChannel,StartPlayAudioLocally - failed to play audio stream + kViEFileInvalidRenderId, // SetRenderTimeoutImage and SetRenderStartImage: Renderer with the provided render id does not exist. + kViEFileInvalidFile, // Can't open the file with provided filename. Is the path and file format correct? + kViEFileInvalidCapture, // Can't use ViEPicture. Is the object correct? + kViEFileSetRenderTimeoutError, // SetRenderTimeoutImage- Please see log file. + kViEFileInvalidCaptureId, // SetCaptureDeviceImage capture id does not exist. + kViEFileSetCaptureImageError, // SetCaptureDeviceImage error. Please see log file. + kViEFileSetStartImageError, // SetRenderStartImage error. Please see log file. + kViEFileUnknownError, // An unknown error has occurred. Check the log file. + + //ViENetwork + kViENetworkInvalidChannelId = 12500, // No Channel exist with the provided channel id. + kViENetworkAlreadyReceiving, // SetLocalReceiver: Can not change ports while receiving. + kViENetworkLocalReceiverNotSet, // GetLocalReceiver: SetLocalReceiver not called. + kViENetworkAlreadySending, // SetSendDestination + kViENetworkDestinationNotSet, // GetSendDestination + kViENetworkInvalidArgument, // GetLocalIP- Check function arguments. + kViENetworkSendCodecNotSet, // SetSendGQoS- Need to set the send codec first. + kViENetworkServiceTypeNotSupported, // SetSendGQoS + kViENetworkNotSupported, // SetSendGQoS Not supported on this OS. + kViENetworkObserverAlreadyRegistered, // RegisterObserver + kViENetworkObserverNotRegistered, // SetPeriodicDeadOrAliveStatus - Need to call RegisterObserver first, DeregisterObserver if no observer is registered. + kViENetworkUnknownError, // An unknown error has occurred. Check the log file. + + //ViERTP_RTCP + kViERtpRtcpInvalidChannelId = 12600, // No Channel exist with the provided channel id. + kViERtpRtcpAlreadySending, // The channel is already sending. Need to stop send before calling this API. + kViERtpRtcpNotSending, // The channel needs to be sending in order for this function to work. + kViERtpRtcpRtcpDisabled, // Functions failed because RTCP is disabled. + kViERtpRtcpObserverAlreadyRegistered, // An observer is already registered. Need to deregister the old first. + kViERtpRtcpObserverNotRegistered, // No observer registered. + kViERtpRtcpUnknownError, // An unknown error has occurred. Check the log file. + + //ViEEncryption + kViEEncryptionInvalidChannelId = 12700, // Channel id does not exist. + kViEEncryptionInvalidSrtpParameter, // EnableSRTPSend, EnableSRTPReceive- Check the SRTP parameters. + kViEEncryptionSrtpNotSupported, // This build does not support SRTP. + kViEEncryptionUnknownError, // An unknown error has occurred. Check the log file. + + //ViEImageProcess + kViEImageProcessInvalidChannelId = 12800, // No Channel exist with the provided channel id. + kViEImageProcessInvalidCaptureId, // No capture device exist with the provided capture id. + kViEImageProcessFilterExists, // RegisterCaptureEffectFilter,RegisterSendEffectFilter,RegisterRenderEffectFilter - Effect filter already registered. + kViEImageProcessFilterDoesNotExist, // DeRegisterCaptureEffectFilter,DeRegisterSendEffectFilter,DeRegisterRenderEffectFilter - Effect filter not registered. + kViEImageProcessAlreadyEnabled, // EnableDeflickering,EnableDenoising,EnableColorEnhancement- Function already enabled. + kViEImageProcessAlreadyDisabled, // EnableDeflickering,EnableDenoising,EnableColorEnhancement- Function already disabled. + kViEImageProcessUnknownError // An unknown error has occurred. Check the log file. +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_ERRORS_H_ diff --git a/video_engine/main/interface/vie_external_codec.h b/video_engine/main/interface/vie_external_codec.h new file mode 100644 index 0000000000..28e2767552 --- /dev/null +++ b/video_engine/main/interface/vie_external_codec.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_EXTERNAL_CODEC_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_EXTERNAL_CODEC_H_ + +#include "common_types.h" + +namespace webrtc +{ +class VideoEngine; +class VideoEncoder; +class VideoDecoder; + +// ---------------------------------------------------------------------------- +// ViEExternalCodec +// ---------------------------------------------------------------------------- + +class WEBRTC_DLLEXPORT ViEExternalCodec +{ +public: + static ViEExternalCodec* GetInterface(VideoEngine* videoEngine); + + virtual int Release() = 0; + + virtual int RegisterExternalSendCodec(const int videoChannel, + const unsigned char plType, + VideoEncoder* encoder) = 0; + + virtual int DeRegisterExternalSendCodec(const int videoChannel, + const unsigned char plType) = 0; + + virtual int RegisterExternalReceiveCodec(const int videoChannel, + const unsigned int plType, + VideoDecoder* decoder, + bool decoderRender = false, + int renderDelay = 0) = 0; + + virtual int DeRegisterExternalReceiveCodec(const int videoChannel, + const unsigned char plType) = 0; + +protected: + ViEExternalCodec() {}; + virtual ~ViEExternalCodec() {}; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_EXTERNAL_CODEC_H_ diff --git a/video_engine/main/interface/vie_file.h b/video_engine/main/interface/vie_file.h new file mode 100644 index 0000000000..141254b559 --- /dev/null +++ b/video_engine/main/interface/vie_file.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This sub-API supports the following functionalities: +// - File recording and playing. +// - Snapshots. +// - Background images. + + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_FILE_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_FILE_H_ + +#include "common_types.h" + +namespace webrtc +{ +class VideoEngine; +struct VideoCodec; + +// This structure contains picture data and describes the picture type. +struct ViEPicture +{ + unsigned char* data; + unsigned int size; + unsigned int width; + unsigned int height; + RawVideoType type; + + ViEPicture() + { + data = NULL; + size = 0; + width = 0; + height = 0; + type = kVideoI420; + } + + //call FreePicture to free data + ~ViEPicture() + { + data = NULL; + size = 0; + width = 0; + height = 0; + type = kVideoUnknown; + } +}; + +// This enumerator tells which audio source to use for media files. +enum AudioSource +{ + NO_AUDIO, + MICROPHONE, + PLAYOUT, + VOICECALL +}; + +// This class declares an abstract interface for a user defined observer. It is +// up to the VideoEngine user to implement a derived class which implements the +// observer class. The observer is registered using RegisterObserver() and +// deregistered using DeregisterObserver(). +class WEBRTC_DLLEXPORT ViEFileObserver +{ +public: + // This method is called when the end is reached of a played file. + virtual void PlayFileEnded(const WebRtc_Word32 fileId) = 0; + +protected: + virtual ~ViEFileObserver() {}; +}; + +// ---------------------------------------------------------------------------- +// ViEFile +// ---------------------------------------------------------------------------- + +class WEBRTC_DLLEXPORT ViEFile +{ +public: + // Factory for the ViEFile sub‐API and increases an internal reference + // counter if successful. Returns NULL if the API is not supported or if + // construction fails. + static ViEFile* GetInterface(VideoEngine* videoEngine); + + // Releases the ViEFile sub-API and decreases an internal reference counter. + // Returns the new reference count. This value should be zero + // for all sub-API:s before the VideoEngine object can be safely deleted. + virtual int Release() = 0; + + // Starts playing a video file. + virtual int StartPlayFile(const char* fileNameUTF8, int& fileId, + const bool loop = false, + const FileFormats fileFormat = + kFileFormatAviFile) = 0; + + // Stops a file from being played. + virtual int StopPlayFile(const int fileId) = 0; + + // Registers an instance of a user implementation of the ViEFileObserver. + virtual int RegisterObserver(int fileId, ViEFileObserver& observer) = 0; + + // Removes an already registered instance of ViEFileObserver. + virtual int DeregisterObserver(int fileId, ViEFileObserver& observer) = 0; + + // This function tells which channel, if any, the file should be sent on. + virtual int SendFileOnChannel(const int fileId, const int videoChannel) = 0; + + // Stops a file from being sent on a a channel. + virtual int StopSendFileOnChannel(const int videoChannel) = 0; + + // Starts playing the file audio as microphone input for the specified voice + // channel. + virtual int StartPlayFileAsMicrophone(const int fileId, + const int audioChannel, + bool mixMicrophone = false, + float volumeScaling = 1) = 0; + + // The function stop the audio from being played on a VoiceEngine channel. + virtual int StopPlayFileAsMicrophone(const int fileId, + const int audioChannel) = 0; + + // The function plays and mixes the file audio with the local speaker signal + // for playout. + virtual int StartPlayAudioLocally(const int fileId, const int audioChannel, + float volumeScaling = 1) = 0; + + // Stops the audio from a file from being played locally. + virtual int StopPlayAudioLocally(const int fileId, + const int audioChannel) = 0; + + // This function starts recording the video transmitted to another endpoint. + virtual int StartRecordOutgoingVideo(const int videoChannel, + const char* fileNameUTF8, + AudioSource audioSource, + const CodecInst& audioCodec, + const VideoCodec& videoCodec, + const FileFormats fileFormat = + kFileFormatAviFile) =0; + + // This function starts recording the incoming video stream on a channel. + virtual int StartRecordIncomingVideo(const int videoChannel, + const char* fileNameUTF8, + AudioSource audioSource, + const CodecInst& audioCodec, + const VideoCodec& videoCodec, + const FileFormats fileFormat = + kFileFormatAviFile) = 0; + + // Stops the file recording of the outgoing stream. + virtual int StopRecordOutgoingVideo(const int videoChannel) = 0; + + // Stops the file recording of the incoming stream. + virtual int StopRecordIncomingVideo(const int videoChannel) = 0; + + // Gets the audio codec, video codec and file format of a recorded file. + virtual int GetFileInformation(const char* fileName, + VideoCodec& videoCodec, + CodecInst& audioCodec, + const FileFormats fileFormat = + kFileFormatAviFile) = 0; + + // The function takes a snapshot of the last rendered image for a video + // channel. + virtual int GetRenderSnapshot(const int videoChannel, + const char* fileNameUTF8) = 0; + + // The function takes a snapshot of the last rendered image for a video + // channel + virtual int GetRenderSnapshot(const int videoChannel, + ViEPicture& picture) = 0; + + // The function takes a snapshot of the last captured image by a specified + // capture device. + virtual int GetCaptureDeviceSnapshot(const int captureId, + const char* fileNameUTF8) = 0; + + // The function takes a snapshot of the last captured image by a specified + // capture device. + virtual int GetCaptureDeviceSnapshot(const int captureId, + ViEPicture& picture) = 0; + + // This function sets a jpg image to show before the first frame is captured + // by the capture device. This frame will be encoded and transmitted to a + // possible receiver + virtual int SetCaptureDeviceImage(const int captureId, + const char* fileNameUTF8) = 0; + + // This function sets an image to show before the first frame is captured by + // the capture device. This frame will be encoded and transmitted to a + // possible receiver + virtual int SetCaptureDeviceImage(const int captureId, + const ViEPicture& picture) = 0; + + virtual int FreePicture(ViEPicture& picture) = 0; + + // This function sets a jpg image to render before the first received video + // frame is decoded for a specified channel. + virtual int SetRenderStartImage(const int videoChannel, + const char* fileNameUTF8) = 0; + + // This function sets an image to render before the first received video + // frame is decoded for a specified channel. + virtual int SetRenderStartImage(const int videoChannel, + const ViEPicture& picture) = 0; + + // This function sets a jpg image to render if no frame is decoded for a + // specified time interval. + virtual int SetRenderTimeoutImage(const int videoChannel, + const char* fileNameUTF8, + const unsigned int timeoutMs = 1000) = 0; + + // This function sets an image to render if no frame is decoded for a + // specified time interval. + virtual int SetRenderTimeoutImage(const int videoChannel, + const ViEPicture& picture, + const unsigned int timeoutMs) = 0; + +protected: + ViEFile() {}; + virtual ~ViEFile() {}; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_FILE_H_ diff --git a/video_engine/main/interface/vie_image_process.h b/video_engine/main/interface/vie_image_process.h new file mode 100644 index 0000000000..c1b79deca4 --- /dev/null +++ b/video_engine/main/interface/vie_image_process.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This sub-API supports the following functionalities: +// - Effect filters +// - Deflickering +// - Denoising +// - Color enhancement + + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_IMAGE_PROCESS_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_IMAGE_PROCESS_H_ + +#include "common_types.h" + +namespace webrtc +{ +class VideoEngine; + +// ---------------------------------------------------------------------------- +// ViEEffectFilter +// ---------------------------------------------------------------------------- + +// This class declares an abstract interface for a user defined effect filter. +// The effect filter is registered using RegisterCaptureEffectFilter(), +// RegisterSendEffectFilter() or RegisterRenderEffectFilter() and deregistered +// with the corresponding deregister function. +class WEBRTC_DLLEXPORT ViEEffectFilter +{ +public: + // This method is called with an I420 video frame allowing the user to + // modify the video frame. + virtual int Transform(int size, unsigned char* frameBuffer, + unsigned int timeStamp90KHz, unsigned int width, + unsigned int height) = 0; +protected: + ViEEffectFilter() {} + virtual ~ViEEffectFilter(){} +}; + +// ---------------------------------------------------------------------------- +// ViEImageProcess +// ---------------------------------------------------------------------------- + +class WEBRTC_DLLEXPORT ViEImageProcess +{ +public: + // Factory for the ViEImageProcess sub‐API and increases an internal + // reference counter if successful. Returns NULL if the API is not supported + // or if construction fails. + static ViEImageProcess* GetInterface(VideoEngine* videoEngine); + + // Releases the ViEImageProcess sub-API and decreases an internal reference + // counter. Returns the new reference count. This value should be zero + // for all sub-API:s before the VideoEngine object can be safely deleted. + virtual int Release() = 0; + + // This function registers a EffectFilter to use for a specified capture + // device. + virtual int RegisterCaptureEffectFilter(const int captureId, + ViEEffectFilter& captureFilter) = 0; + + // This function deregisters a EffectFilter for a specified capture device. + virtual int DeregisterCaptureEffectFilter(const int captureId) = 0; + + // This function registers an EffectFilter to use for a specified channel. + virtual int RegisterSendEffectFilter(const int videoChannel, + ViEEffectFilter& sendFilter) = 0; + + // This function deregisters a send effect filter for a specified channel. + virtual int DeregisterSendEffectFilter(const int videoChannel) = 0; + + // This function registers a EffectFilter to use for the rendered video + // stream on an incoming channel. + virtual int RegisterRenderEffectFilter(const int videoChannel, + ViEEffectFilter& renderFilter) = 0; + + // This function deregisters a render effect filter for a specified channel. + virtual int DeregisterRenderEffectFilter(const int videoChannel) = 0; + + // All cameras run the risk of getting in almost perfect sync with + // florescent lamps, which will result in a very annoying flickering of the + // image. Most cameras have some type of filter to protect against this but + // not all of them succeed. Enabling this function will remove the flicker. + virtual int EnableDeflickering(const int captureId, const bool enable) = 0; + + // Some cameras produce very noisy captured images, especially in low‐light + // conditions. This functionality will reduce the camera noise. + virtual int EnableDenoising(const int captureId, const bool enable) = 0; + + // This function enhances the colors on the decoded video stream, enabled by + // default. + virtual int EnableColorEnhancement(const int videoChannel, + const bool enable) = 0; + +protected: + ViEImageProcess() {}; + virtual ~ViEImageProcess() {}; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_IMAGE_PROCESS_H_ diff --git a/video_engine/main/interface/vie_network.h b/video_engine/main/interface/vie_network.h new file mode 100644 index 0000000000..aa97053e5c --- /dev/null +++ b/video_engine/main/interface/vie_network.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_NETWORK_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_NETWORK_H_ + +// This sub-API supports the following functionalities: +// - Configuring send and receive addresses. +// - External transport support. +// - Port and address filters. +// - Windows GQoS functions and ToS functions. +// - Packet timeout notification. +// - Dead‐or‐Alive connection observations. + + +#include "common_types.h" + +namespace webrtc +{ +class VideoEngine; +class Transport; + +// ---------------------------------------------------------------------------- +// ViENetworkObserver +// ---------------------------------------------------------------------------- + +// This enumerator describes VideoEngine packet timeout states. +enum ViEPacketTimeout +{ + NoPacket = 0, + PacketReceived = 1 +}; + +// This class declares an abstract interface for a user defined observer. It is +// up to the VideoEngine user to implement a derived class which implements the +// observer class. The observer is registered using RegisterObserver() and +// deregistered using DeregisterObserver(). +class WEBRTC_DLLEXPORT ViENetworkObserver +{ +public: + // This method will be called periodically delivering a dead‐or‐alive + // decision for a specified channel. + virtual void OnPeriodicDeadOrAlive(const int videoChannel, + const bool alive) = 0; + + // This method is called once if a packet timeout occurred. + virtual void PacketTimeout(const int videoChannel, + const ViEPacketTimeout timeout) = 0; +protected: + virtual ~ViENetworkObserver() {}; +}; + +// ---------------------------------------------------------------------------- +// ViENetwork +// ---------------------------------------------------------------------------- + +class WEBRTC_DLLEXPORT ViENetwork +{ +public: + // Default values + enum + { + KDefaultSampleTimeSeconds = 2 + }; + + // Factory for the ViENetwork sub‐API and increases an internal reference + // counter if successful. Returns NULL if the API is not supported or if + // construction fails. + static ViENetwork* GetInterface(VideoEngine* videoEngine); + + // Releases the ViENetwork sub-API and decreases an internal reference + // counter.Returns the new reference count. This value should be zero + // for all sub-API:s before the VideoEngine object can be safely deleted. + virtual int Release() = 0; + + // Specifies the ports to receive RTP packets on. It is also possible to set + // port for RTCP and local IP address. + virtual int SetLocalReceiver(const int videoChannel, + const unsigned short rtpPort, + const unsigned short rtcpPort = 0, + const char* ipAddress = NULL) = 0; + + // Gets the local receiver ports and address for a specified channel. + virtual int GetLocalReceiver(const int videoChannel, + unsigned short& rtpPort, + unsigned short& rtcpPort, char* ipAddress) = 0; + + // Specifies the destination port and IP address for a specified channel. + virtual int SetSendDestination(const int videoChannel, + const char* ipAddress, + const unsigned short rtpPort, + const unsigned short rtcpPort = 0, + const unsigned short sourceRtpPort = 0, + const unsigned short sourceRtcpPort = 0) = 0; + + // Get the destination port and address for a specified channel. + virtual int GetSendDestination(const int videoChannel, char* ipAddress, + unsigned short& rtpPort, + unsigned short& rtcpPort, + unsigned short& sourceRtpPort, + unsigned short& sourceRtcpPort) = 0; + + // This function registers a user implementation of Transport to use for + // sending RTP and RTCP packets on this channel. + virtual int RegisterSendTransport(const int videoChannel, + Transport& transport) = 0; + + // This function deregisters a used Transport for a specified channel. + virtual int DeregisterSendTransport(const int videoChannel) = 0; + + // When using external transport for a channel, received RTP packets should + // be passed to VideoEngine using this function. The input should contain + // the RTP header and payload. + virtual int ReceivedRTPPacket(const int videoChannel, const void* data, + const int length) = 0; + + // When using external transport for a channel, received RTCP packets should + // be passed to VideoEngine using this function. + virtual int ReceivedRTCPPacket(const int videoChannel, const void* data, + const int length) = 0; + + // Gets the source ports and IP address of the incoming stream for a + // specified channel. + virtual int GetSourceInfo(const int videoChannel, unsigned short& rtpPort, + unsigned short& rtcpPort, char* ipAddress, + unsigned int ipAddressLength) = 0; + + // Gets the local IP address, in string format. + virtual int GetLocalIP(char ipAddress[64], bool ipv6 = false) = 0; + + // Enables IPv6, instead of IPv4, for a specified channel. + virtual int EnableIPv6(int videoChannel) = 0; + + // The function returns true if IPv6 is enabled, false otherwise. + virtual bool IsIPv6Enabled(int videoChannel) = 0; + + // Enables a port and IP address filtering for incoming packets on a + // specific channel. + virtual int SetSourceFilter(const int videoChannel, + const unsigned short rtpPort, + const unsigned short rtcpPort = 0, + const char* ipAddress = NULL) = 0; + + // Gets current port and IP address filter for a specified channel. + virtual int GetSourceFilter(const int videoChannel, unsigned short& rtpPort, + unsigned short& rtcpPort, char* ipAddress) = 0; + + // This function sets the six‐bit Differentiated Services Code Point (DSCP) + // in the IP header of the outgoing stream for a specific channel. + // Windows and Linux only. + virtual int SetSendToS(const int videoChannel, const int DSCP, + const bool useSetSockOpt = false) = 0; + + // Retrieves the six‐bit Differentiated Services Code Point (DSCP) in the IP + // header of the outgoing stream for a specific channel. + virtual int GetSendToS(const int videoChannel, int& DSCP, + bool& useSetSockOpt) = 0; + + // This function sets the Generic Quality of Service (GQoS) service level. + // The Windows operating system then maps to a Differentiated Services Code + // Point (DSCP) and to an 802.1p setting. Windows only. + virtual int SetSendGQoS(const int videoChannel, const bool enable, + const int serviceType, + const int overrideDSCP = 0) = 0; + + // This function retrieves the currently set GQoS service level for a + // specific channel. + virtual int GetSendGQoS(const int videoChannel, bool& enabled, + int& serviceType, int& overrideDSCP) = 0; + + // This function sets the Maximum Transition Unit (MTU) for a channel. The + // RTP packet will be packetized based on this MTU to optimize performance + // over the network. + virtual int SetMTU(int videoChannel, unsigned int mtu) = 0; + + // This function enables or disables warning reports if packets have not + // been received for a specified time interval. + virtual int SetPacketTimeoutNotification(const int videoChannel, + bool enable, + int timeoutSeconds) = 0; + + // Registers an instance of a user implementation of the ViENetwork + // observer. + virtual int RegisterObserver(const int videoChannel, + ViENetworkObserver& observer) = 0; + + // Removes a registered instance of ViENetworkObserver. + virtual int DeregisterObserver(const int videoChannel) = 0; + + // This function enables or disables the periodic dead‐or‐alive callback + // functionality for a specified channel. + virtual int SetPeriodicDeadOrAliveStatus( + const int videoChannel, const bool enable, + const unsigned int sampleTimeSeconds = KDefaultSampleTimeSeconds) = 0; + + // This function handles sending a raw UDP data packet over an existing RTP + // or RTCP socket. + virtual int SendUDPPacket(const int videoChannel, const void* data, + const unsigned int length, int& transmittedBytes, + bool useRtcpSocket = false) = 0; + +protected: + ViENetwork() {}; + virtual ~ViENetwork() {}; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_NETWORK_H_ diff --git a/video_engine/main/interface/vie_render.h b/video_engine/main/interface/vie_render.h new file mode 100644 index 0000000000..ef2631dafa --- /dev/null +++ b/video_engine/main/interface/vie_render.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This sub-API supports the following functionalities: +// - Specify render destinations for incoming video streams, capture devices +// and files. +// - Configuring render streams. + + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_RENDER_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_RENDER_H_ + +#include "common_types.h" + +namespace webrtc +{ + +class VideoRender; +class VideoEngine; + +// ---------------------------------------------------------------------------- +// ExternalRenderer +// ---------------------------------------------------------------------------- + +// This class declares an abstract interface to be used for external renderers. +// The user implemented derived class is registered using AddRenderer(). +class WEBRTC_DLLEXPORT ExternalRenderer +{ +public: + // This method will be called when the stream to be rendered changes in + // resolution or number of streams mixed in the image. + virtual int FrameSizeChange(unsigned int width, unsigned int height, + unsigned int numberOfStreams) = 0; + + // This method is called when a new frame should be rendered. + virtual int DeliverFrame(unsigned char* buffer, int bufferSize) = 0; + +protected: + virtual ~ExternalRenderer() {} +}; + +// ---------------------------------------------------------------------------- +// ViERender +// ---------------------------------------------------------------------------- + +class WEBRTC_DLLEXPORT ViERender +{ +public: + // Factory for the ViERender sub‐API and increases an internal reference + // counter if successful. Returns NULL if the API is not supported or if + // construction fails. + static ViERender* GetInterface(VideoEngine* videoEngine); + + // Releases the ViERender sub-API and decreases an internal reference + // counter. Returns the new reference count. This value should be zero + // for all sub-API:s before the VideoEngine object can be safely deleted. + virtual int Release() = 0; + + // Registers render module + virtual int RegisterVideoRenderModule(VideoRender& renderModule) = 0; + + // Deegisters render module + virtual int DeRegisterVideoRenderModule(VideoRender& renderModule) = 0; + + // Sets the render destination for a given render ID. + virtual int AddRenderer(const int renderId, void* window, + const unsigned int zOrder, const float left, + const float top, const float right, + const float bottom) = 0; + + // Removes the renderer for a stream + virtual int RemoveRenderer(const int renderId) = 0; + + // Starts rendering a render stream. + virtual int StartRender(const int renderId) = 0; + + // Stops rendering a render stream. + virtual int StopRender(const int renderId) = 0; + + // Configures an already added render stream. + virtual int ConfigureRender(int renderId, const unsigned int zOrder, + const float left, const float top, + const float right, const float bottom) = 0; + + // This function mirrors the rendered stream left and right or up and down. + virtual int MirrorRenderStream(const int renderId, const bool enable, + const bool mirrorXAxis, + const bool mirrorYAxis) = 0; + + // External render + virtual int AddRenderer(const int renderId, RawVideoType videoInputFormat, + ExternalRenderer* renderer) = 0; + +protected: + ViERender() {}; + virtual ~ViERender() {}; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_RENDER_H_ diff --git a/video_engine/main/interface/vie_rtp_rtcp.h b/video_engine/main/interface/vie_rtp_rtcp.h new file mode 100644 index 0000000000..70bf3b4809 --- /dev/null +++ b/video_engine/main/interface/vie_rtp_rtcp.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This sub-API supports the following functionalities: +// - Callbacks for RTP and RTCP events such as modified SSRC or CSRC. +// - SSRC handling. +// - Transmission of RTCP reports. +// - Obtaining RTCP data from incoming RTCP sender reports. +// - RTP and RTCP statistics (jitter, packet loss, RTT etc.). +// - Forward Error Correction (FEC). +// - RTP Keep‐alive for maintaining the NAT mappings associated to RTP flows. +// - Writing RTP and RTCP packets to binary files for off‐line analysis of the +// call quality. +// - Inserting extra RTP packets into active audio stream. + + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_RTP_RTCP_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_RTP_RTCP_H_ + +#include "common_types.h" + +namespace webrtc +{ +class VideoEngine; + +// This enumerator sets the RTCP mode. +enum ViERTCPMode +{ + kRtcpNone = 0, + kRtcpCompound_RFC4585 = 1, + kRtcpNonCompound_RFC5506 = 2 +}; + +// This enumerator describes the key frame request mode. +enum ViEKeyFrameRequestMethod +{ + kViEKeyFrameRequestNone = 0, + kViEKeyFrameRequestPliRtcp = 1, + kViEKeyFrameRequestFirRtp = 2, + kViEKeyFrameRequestFirRtcp = 3 +}; + +// ---------------------------------------------------------------------------- +// ViERTPObserver +// ---------------------------------------------------------------------------- + +// This class declares an abstract interface for a user defined observer. It is +// up to the VideoEngine user to implement a derived class which implements the +// observer class. The observer is registered using RegisterRTPObserver() and +// deregistered using DeregisterRTPObserver(). +class WEBRTC_DLLEXPORT ViERTPObserver +{ +public: + // This method is called if SSRC of the incoming stream is changed. + virtual void IncomingSSRCChanged(const int videoChannel, + const unsigned int SSRC) = 0; + + // This method is called if a field in CSRC changes or if the number of + // CSRCs changes. + virtual void IncomingCSRCChanged(const int videoChannel, + const unsigned int CSRC, + const bool added) = 0; +protected: + virtual ~ViERTPObserver() {} +}; + +// ---------------------------------------------------------------------------- +// ViERTCPObserver +// ---------------------------------------------------------------------------- + +// This class declares an abstract interface for a user defined observer. It is +// up to the VideoEngine user to implement a derived class which implements the +// observer class. The observer is registered using RegisterRTCPObserver() and +// deregistered using DeregisterRTCPObserver(). + +class WEBRTC_DLLEXPORT ViERTCPObserver +{ +public: + // This method is called if a application-defined RTCP packet has been + // received. + virtual void OnApplicationDataReceived( + const int videoChannel, const unsigned char subType, + const unsigned int name, const char* data, + const unsigned short dataLengthInBytes) = 0; +protected: + virtual ~ViERTCPObserver() {} +}; + +// +class WEBRTC_DLLEXPORT ViERTP_RTCP +{ +public: + // Default values + enum + { + KDefaultDeltaTransmitTimeSeconds = 15 + }; + enum + { + KMaxRTCPCNameLength = 256 + }; + + // Factory for the ViERTP_RTCP sub‐API and increases an internal reference + // counter if successful. Returns NULL if the API is not supported or if + // construction fails. + static ViERTP_RTCP* GetInterface(VideoEngine* videoEngine); + + // Releases the ViERTP_RTCP sub-API and decreases an internal reference + // counter. Returns the new reference count. This value should be zero + // for all sub-API:s before the VideoEngine object can be safely deleted. + virtual int Release() = 0; + + // This function enables you to specify the RTP synchronization source + // identifier (SSRC) explicitly. + virtual int SetLocalSSRC(const int videoChannel, + const unsigned int SSRC) = 0; + + // This function gets the SSRC for the outgoing RTP stream for the specified + // channel. + virtual int GetLocalSSRC(const int videoChannel, + unsigned int& SSRC) const = 0; + + // This function gets the SSRC for the incoming RTP stream for the specified + // channel. + virtual int GetRemoteSSRC(const int videoChannel, + unsigned int& SSRC) const = 0; + + // This function returns the CSRCs of the incoming RTP packets. + virtual int GetRemoteCSRCs(const int videoChannel, + unsigned int CSRCs[kRtpCsrcSize]) const = 0; + + // This function enables manual initialization of the sequence number. The + // start sequence number is normally a random number. + virtual int SetStartSequenceNumber(const int videoChannel, + unsigned short sequenceNumber) = 0; + + // This function sets the RTCP status for the specified channel. + // Default mode is kRtcpCompound_RFC4585. + virtual int SetRTCPStatus(const int videoChannel, + const ViERTCPMode rtcpMode) = 0; + + // This function gets the RTCP status for the specified channel. + virtual int GetRTCPStatus(const int videoChannel, + ViERTCPMode& rtcpMode) = 0; + + // This function sets the RTCP canonical name (CNAME) for the RTCP reports + // on a specific channel. + virtual int SetRTCPCName(const int videoChannel, + const char rtcpCName[KMaxRTCPCNameLength]) = 0; + + // This function gets the RTCP canonical name (CNAME) for the RTCP reports + // sent the specified channel. + virtual int GetRTCPCName(const int videoChannel, + char rtcpCName[KMaxRTCPCNameLength]) = 0; + + // This function gets the RTCP canonical name (CNAME) for the RTCP reports + // received on the specified channel. + virtual int GetRemoteRTCPCName( + const int videoChannel, char rtcpCName[KMaxRTCPCNameLength]) const = 0; + + // This function sends an RTCP APP packet on a specific channel. + virtual int SendApplicationDefinedRTCPPacket( + const int videoChannel, const unsigned char subType, + unsigned int name, const char* data, + unsigned short dataLengthInBytes) = 0; + + // This function enables Negative Acknowledgement (NACK) using RTCP, + // implemented based on RFC 4585. NACK retransmits RTP packets if lost on + // the network. This creates a lossless transport at the expense of delay. + // If using NACK, NACK should be enabled on both endpoints in a call. + virtual int SetNACKStatus(const int videoChannel, const bool enable) = 0; + + // This function enables Forward Error Correction (FEC) using RTCP, + // implemented based on RFC 5109, to improve packet loss robustness. Extra + // FEC packets are sent together with the usual media packets, hence + // part of the bitrate will be used for FEC packets. + virtual int SetFECStatus(const int videoChannel, const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC) = 0; + + // This function enables RTCP key frame requests. + virtual int SetKeyFrameRequestMethod( + const int videoChannel, const ViEKeyFrameRequestMethod method) = 0; + + // This function enables signaling of temporary bitrate constraints using + // RTCP, implemented based on RFC4585. + virtual int SetTMMBRStatus(const int videoChannel, const bool enable) = 0; + + // The function gets statistics from the received RTCP report. + virtual int GetReceivedRTCPStatistics( + const int videoChannel, unsigned short& fractionLost, + unsigned int& cumulativeLost, unsigned int& extendedMax, + unsigned int& jitter, int& rttMs) const = 0; + + // The function gets statistics from the RTCP report sent to the receiver. + virtual int GetSentRTCPStatistics(const int videoChannel, + unsigned short& fractionLost, + unsigned int& cumulativeLost, + unsigned int& extendedMax, + unsigned int& jitter, + int& rttMs) const = 0; + + // The function gets statistics from the sent and received RTP streams. + virtual int GetRTPStatistics(const int videoChannel, + unsigned int& bytesSent, + unsigned int& packetsSent, + unsigned int& bytesReceived, + unsigned int& packetsReceived) const = 0; + + // This function enables or disables an RTP keep-alive mechanism which can + // be used to maintain an existing Network Address Translator (NAT) mapping + // while regular RTP is no longer transmitted. + virtual int SetRTPKeepAliveStatus( + const int videoChannel, bool enable, const char unknownPayloadType, + const unsigned int deltaTransmitTimeSeconds = + KDefaultDeltaTransmitTimeSeconds) = 0; + + // This function gets the RTP keep-alive status. + virtual int GetRTPKeepAliveStatus( + const int videoChannel, bool& enabled, char& unkownPayloadType, + unsigned int& deltaTransmitTimeSeconds) = 0; + + // This function enables capturing of RTP packets to a binary file on a + // specific channel and for a given direction. The file can later be + // replayed using e.g. RTP Tools rtpplay since the binary file format is + // compatible with the rtpdump format. + virtual int StartRTPDump(const int videoChannel, + const char fileNameUTF8[1024], + RTPDirections direction) = 0; + + // This function disables capturing of RTP packets to a binary file on a + // specific channel and for a given direction. + virtual int StopRTPDump(const int videoChannel, + RTPDirections direction) = 0; + + // Registers an instance of a user implementation of the ViERTPObserver. + virtual int RegisterRTPObserver(const int videoChannel, + ViERTPObserver& observer) = 0; + + // Removes a registered instance of ViERTPObserver. + virtual int DeregisterRTPObserver(const int videoChannel) = 0; + + // Registers an instance of a user implementation of the ViERTCPObserver. + virtual int RegisterRTCPObserver(const int videoChannel, + ViERTCPObserver& observer) = 0; + + // Removes a registered instance of ViERTCPObserver. + virtual int DeregisterRTCPObserver(const int videoChannel) = 0; + +protected: + ViERTP_RTCP() {}; + virtual ~ViERTP_RTCP() {}; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_INTERFACE_VIE_RTP_RTCP_H_ diff --git a/video_engine/main/source/video_engine_core.gyp b/video_engine/main/source/video_engine_core.gyp new file mode 100644 index 0000000000..0f73a2eee1 --- /dev/null +++ b/video_engine/main/source/video_engine_core.gyp @@ -0,0 +1,133 @@ +# Copyright (c) 2009 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. + +{ + 'includes': [ + '../../../common_settings.gypi', # Common settings + ], + 'targets': [ + { + 'target_name': 'video_engine_core', + 'type': '<(library)', + 'dependencies': [ + + ## common_video + '../../../common_video/vplib/main/source/vplib.gyp:webrtc_vplib', + '../../../common_video/jpeg/main/source/jpeg.gyp:webrtc_jpeg', + + ## ModulesShared + '../../../modules/media_file/source/media_file.gyp:media_file', + '../../../modules/rtp_rtcp/source/rtp_rtcp.gyp:rtp_rtcp', + '../../../modules/udp_transport/source/udp_transport.gyp:udp_transport', + '../../../modules/utility/source/utility.gyp:webrtc_utility', + + ## ModulesVideo + '../../../modules/video_coding/main/source/video_coding.gyp:webrtc_video_coding', + '../../../modules/video_processing/main/source/video_processing.gyp:video_processing', + '../../../modules/video_render/main/source/video_render.gyp:video_render_module', + + ## VoiceEngine + '../../../voice_engine/main/source/voice_engine_core.gyp:voice_engine_core', + + ## system_wrappers_2005 + '../../../system_wrappers/source/system_wrappers.gyp:system_wrappers', + ], + 'include_dirs': [ + '../interface', + '../../../modules/video_capture/main/interface', + '../../../modules/video_render/main/interface', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../interface', + ], + }, + 'sources': [ + # interface + '../interface/vie_base.h', + '../interface/vie_capture.h', + '../interface/vie_codec.h', + '../interface/vie_encryption.h', + '../interface/vie_errors.h', + '../interface/vie_external_codec.h', + '../interface/vie_file.h', + '../interface/vie_image_process.h', + '../interface/vie_network.h', + '../interface/vie_render.h', + '../interface/vie_rtp_rtcp.h', + + # headers + 'vie_base_impl.h', + 'vie_capture_impl.h', + 'vie_codec_impl.h', + 'vie_defines.h', + 'vie_encryption_impl.h', + 'vie_external_codec_impl.h', + 'vie_file_impl.h', + 'vie_image_process_impl.h', + 'vie_impl.h', + 'vie_network_impl.h', + 'vie_ref_count.h', + 'vie_render_impl.h', + 'vie_rtp_rtcp_impl.h', + 'vie_shared_data.h', + 'vie_capturer.h', + 'vie_channel.h', + 'vie_channel_manager.h', + 'vie_encoder.h', + 'vie_file_image.h', + 'vie_file_player.h', + 'vie_file_recorder.h', + 'vie_frame_provider_base.h', + 'vie_input_manager.h', + 'vie_manager_base.h', + 'vie_performance_monitor.h', + 'vie_receiver.h', + 'vie_renderer.h', + 'vie_render_manager.h', + 'vie_sender.h', + 'vie_sync_module.h', + + # ViE + 'vie_base_impl.cc', + 'vie_capture_impl.cc', + 'vie_codec_impl.cc', + 'vie_encryption_impl.cc', + 'vie_external_codec_impl.cc', + 'vie_file_impl.cc', + 'vie_image_process_impl.cc', + 'vie_impl.cc', + 'vie_network_impl.cc', + 'vie_ref_count.cc', + 'vie_render_impl.cc', + 'vie_rtp_rtcp_impl.cc', + 'vie_shared_data.cc', + + # ViE + 'vie_capturer.cc', + 'vie_channel.cc', + 'vie_channel_manager.cc', + 'vie_encoder.cc', + 'vie_file_image.cc', + 'vie_file_player.cc', + 'vie_file_recorder.cc', + 'vie_frame_provider_base.cc', + 'vie_input_manager.cc', + 'vie_manager_base.cc', + 'vie_performance_monitor.cc', + 'vie_receiver.cc', + 'vie_renderer.cc', + 'vie_render_manager.cc', + 'vie_sender.cc', + 'vie_sync_module.cc', + ], # source + }, + ], +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/video_engine/main/source/vie_base_impl.cc b/video_engine/main/source/vie_base_impl.cc new file mode 100644 index 0000000000..7d7edf829e --- /dev/null +++ b/video_engine/main/source/vie_base_impl.cc @@ -0,0 +1,838 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_base_impl.cc + */ + +#include "vie_base_impl.h" + +// Defines +#include "engine_configurations.h" +#include "vie_defines.h" + +#include "critical_section_wrapper.h" +#include "trace.h" +#include "vie_errors.h" +#include "vie_impl.h" +#include "vie_shared_data.h" +#include "vie_channel.h" +#include "vie_channel_manager.h" +#include "vie_encoder.h" +#include "vie_input_manager.h" +#include "vie_performance_monitor.h" +#include "rtp_rtcp.h" +#include "video_render.h" +#include "video_coding.h" +#include "video_processing.h" +#include "stdio.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// GetInterface +// ---------------------------------------------------------------------------- + +ViEBase* ViEBase::GetInterface(VideoEngine* videoEngine) +{ + if (videoEngine == NULL) + { + return NULL; + } + VideoEngineImpl* vieImpl = reinterpret_cast (videoEngine); + ViEBaseImpl* vieBaseImpl = vieImpl; + (*vieBaseImpl)++; // Increase ref count + + return vieBaseImpl; +} + +// ---------------------------------------------------------------------------- +// Release +// +// Releases the interface, i.e. reduces the reference counter. The number of +// remaining references is returned, -1 if released too many times. +// ---------------------------------------------------------------------------- +int ViEBaseImpl::Release() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "ViEBase::Release()"); + (*this)--; // Decrease ref count + + WebRtc_Word32 refCount = GetCount(); + if (refCount < 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, + "ViEBase release too many times"); + SetLastError(kViEAPIDoesNotExist); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId, + "ViEBase reference count: %d", refCount); + return refCount; +} + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViEBaseImpl::ViEBaseImpl() : + _viePerformanceMonitor(0) +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViEBaseImpl::ViEBaseImpl() Ctor"); +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViEBaseImpl::~ViEBaseImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViEBaseImpl::ViEBaseImpl() Dtor"); + + _viePerformanceMonitor.Terminate(); +} + +// ---------------------------------------------------------------------------- +// Init +// +// Must be called before any other API is called. +// This API should also reset the state of the enigne to the original state. +// ---------------------------------------------------------------------------- + +int ViEBaseImpl::Init() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, "Init"); + if (IsInitialized()) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, + "Init called twice"); + return 0; + } + + SetInitialized(); + + _viePerformanceMonitor.Init(); + + return 0; +} + +// ---------------------------------------------------------------------------- +// SetVoiceEngine +// +// Connects ViE to a VoE instance. +// ---------------------------------------------------------------------------- + +int ViEBaseImpl::SetVoiceEngine(VoiceEngine* ptrVoiceEngine) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + if (_channelManager.SetVoiceEngine(ptrVoiceEngine) != 0) + { + SetLastError(kViEBaseVoEFailure); + return -1; + } + return 0; + +} + +// ============================================================================ +// Channel functions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// CreateChannel +// +// Creates a new ViE channel +// ---------------------------------------------------------------------------- + +int ViEBaseImpl::CreateChannel(int& videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + if (_channelManager.CreateChannel(videoChannel) == -1) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Could not create channel", __FUNCTION__); + videoChannel = -1; + SetLastError(kViEBaseChannelCreationFailed); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: channel created: %d", __FUNCTION__, videoChannel); + return 0; +} + +// ---------------------------------------------------------------------------- +// CreateChannel +// +// Creates a new channel using the same capture device and encoder as +// the original channel. +// ---------------------------------------------------------------------------- + +int ViEBaseImpl::CreateChannel(int& videoChannel, int originalChannel) +{ + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + ViEChannelManagerScoped cs(_channelManager); + + if (!cs.Channel(originalChannel)) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - originalChannel does not exist.", __FUNCTION__, + _instanceId); + SetLastError(kViEBaseInvalidChannelId); + return -1; + } + + if (_channelManager.CreateChannel(videoChannel, + originalChannel) == -1) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Could not create channel", __FUNCTION__); + videoChannel = -1; + SetLastError(kViEBaseChannelCreationFailed); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: channel created: %d", __FUNCTION__, videoChannel); + return 0; +} + +// ---------------------------------------------------------------------------- +// DeleteChannel +// +// Deleted a ViE channel +// ---------------------------------------------------------------------------- + +int ViEBaseImpl::DeleteChannel(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s(%d)", + __FUNCTION__, videoChannel); + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + { + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + // No such channel + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViEBaseInvalidChannelId); + return -1; + } + + // Deregister the ViEEncoder if no other channel is using it. + ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel); + if (cs.ChannelUsingViEEncoder(videoChannel) == false) + { + // No other channels using this ViEEncoder. + // Disconnect the channel encoder from possible input. + // capture or file. + ViEInputManagerScoped is(_inputManager); + ViEFrameProviderBase* provider = is.FrameProvider(ptrViEEncoder); + if (provider) + { + provider->DeregisterFrameCallback(ptrViEEncoder); + } + } + } + if (_channelManager.DeleteChannel(videoChannel) == -1) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Could not delete channel %d", __FUNCTION__, + videoChannel); + SetLastError(kViEBaseUnknownError); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: channel deleted: %d", __FUNCTION__, videoChannel); + return 0; +} + +// ---------------------------------------------------------------------------- +// ConnectAudioChannel +// +// Connects a ViE channel with a VoE channel +// ---------------------------------------------------------------------------- + +int ViEBaseImpl::ConnectAudioChannel(const int videoChannel, + const int audioChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s(%d)", + __FUNCTION__, videoChannel); + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + ViEChannelManagerScoped cs(_channelManager); + if (cs.Channel(videoChannel) == NULL) + { + // No such channel + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: channel %d doesn't exist", __FUNCTION__, videoChannel); + SetLastError(kViEBaseInvalidChannelId); + return -1; + } + + if (_channelManager.ConnectVoiceChannel(videoChannel, audioChannel) != 0) + { + SetLastError(kViEBaseVoEFailure); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DisconnectAudioChannel +// +// Disconnects a previously connected ViE and VoE channel pair +// ---------------------------------------------------------------------------- + +int ViEBaseImpl::DisconnectAudioChannel(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s(%d)", + __FUNCTION__, videoChannel); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + ViEChannelManagerScoped cs(_channelManager); + if (cs.Channel(videoChannel) == NULL) + { + // No such channel + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: channel %d doesn't exist", __FUNCTION__, videoChannel); + SetLastError(kViEBaseInvalidChannelId); + return -1; + } + + if (_channelManager.DisconnectVoiceChannel(videoChannel) != 0) + { + SetLastError(kViEBaseVoEFailure); + return -1; + } + return 0; +} + +// ============================================================================ +// Start and stop +// ============================================================================ + +// ---------------------------------------------------------------------------- +// StartSend +// +// Starts sending on videoChannel and also starts the encoder. +// ---------------------------------------------------------------------------- +int ViEBaseImpl::StartSend(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId, + videoChannel), + "%s(channel: %d)", __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d does not exist", __FUNCTION__, videoChannel); + SetLastError(kViEBaseInvalidChannelId); + return -1; + } + ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel); + if (ptrViEEncoder == NULL) + { + assert(false); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Could not find encoder for channel %d", __FUNCTION__, + videoChannel); + return -1; + } + + // Make sure we start with a key frame... + ptrViEEncoder->Pause(); + WebRtc_Word32 error = ptrViEChannel->StartSend(); + if (error != 0) + { + // Restart the encoder, if it was stopped + ptrViEEncoder->Restart(); + + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Could not start sending on channel %d", __FUNCTION__, + videoChannel); + if (error == kViEBaseAlreadySending) + { + SetLastError(kViEBaseAlreadySending); + } + SetLastError(kViEBaseUnknownError); + return -1; + } + + // Trigger the key frame and restart + ptrViEEncoder->SendKeyFrame(); + ptrViEEncoder->Restart(); + return 0; +} + +// ---------------------------------------------------------------------------- +// StopSend +// +// Stops sending on the channel. This will also stop the encoder for the +// channel, if not shared with still active channels. +// ---------------------------------------------------------------------------- +int ViEBaseImpl::StopSend(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d does not exist", __FUNCTION__, videoChannel); + SetLastError(kViEBaseInvalidChannelId); + return -1; + } + + WebRtc_Word32 error = ptrViEChannel->StopSend(); + if (error != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Could not stop sending on channel %d", __FUNCTION__, + videoChannel); + if (error == kViEBaseNotSending) + { + SetLastError(kViEBaseNotSending); + } + else + { + SetLastError(kViEBaseUnknownError); + } + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// StartReceive +// +// Stops receiving on the channel. This will also start the decoder. +// ---------------------------------------------------------------------------- +int ViEBaseImpl::StartReceive(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d does not exist", __FUNCTION__, videoChannel); + SetLastError(kViEBaseInvalidChannelId); + return -1; + } + if (ptrViEChannel->Receiving()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d already receive.", __FUNCTION__, + videoChannel); + SetLastError(kViEBaseAlreadyReceiving); + return -1; + } + if (ptrViEChannel->StartReceive() != 0) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// StopReceive +// +// Stops receiving on the channel. No decoding will be done. +// ---------------------------------------------------------------------------- +int ViEBaseImpl::StopReceive(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d does not exist", __FUNCTION__, videoChannel); + SetLastError(kViEBaseInvalidChannelId); + return -1; + } + if (ptrViEChannel->StopReceive() != 0) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// Channel functions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// RegisterObserver +// +// Registers a customer implemented ViE observer +// ---------------------------------------------------------------------------- + +int ViEBaseImpl::RegisterObserver(ViEBaseObserver& observer) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + if (_viePerformanceMonitor.ViEBaseObserverRegistered()) + { + SetLastError(kViEBaseObserverAlreadyRegistered); + return -1; + } + + return _viePerformanceMonitor.RegisterViEBaseObserver(&observer); +} + +// ---------------------------------------------------------------------------- +// DeregisterObserver +// +// Deregisters an observer +// ---------------------------------------------------------------------------- + +int ViEBaseImpl::DeregisterObserver() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + + if (!_viePerformanceMonitor.ViEBaseObserverRegistered()) + { + SetLastError(kViEBaseObserverNotRegistered); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + "%s No observer registered.", __FUNCTION__); + return -1; + } + return _viePerformanceMonitor.RegisterViEBaseObserver(NULL); +} + +// ============================================================================ +// Info functions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// GetVersion +// +// Writes version information in 'version' +// ---------------------------------------------------------------------------- + +int ViEBaseImpl::GetVersion(char version[1024]) +{ + + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "GetVersion(version=?)"); + assert(kViEVersionMaxMessageSize == 1024); + + if (version == NULL) + { + SetLastError(kViEBaseInvalidArgument); + return (-1); + } + + char versionBuf[kViEVersionMaxMessageSize]; + char* versionPtr = versionBuf; + + WebRtc_Word32 len = 0; // does not include terminating NULL + WebRtc_Word32 accLen = 0; + + len = AddViEVersion(versionPtr); + if (len == -1) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + versionPtr += len; + accLen += len; + assert(accLen < kViEVersionMaxMessageSize); + + len = AddBuildInfo(versionPtr); + if (len == -1) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + versionPtr += len; + accLen += len; + assert(accLen < kViEVersionMaxMessageSize); + +#ifdef WEBRTC_EXTERNAL_TRANSPORT + len = AddExternalTransportBuild(versionPtr); + if (len == -1) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + versionPtr += len; + accLen += len; + assert(accLen < kViEVersionMaxMessageSize); +#endif + + len = AddVCMVersion(versionPtr); + if (len == -1) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + versionPtr += len; + accLen += len; + assert(accLen < kViEVersionMaxMessageSize); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + len = AddSocketModuleVersion(versionPtr); + if (len == -1) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + versionPtr += len; + accLen += len; + assert(accLen < kViEVersionMaxMessageSize); +#endif + +#ifdef WEBRTC_SRTP + len = AddSRTPModuleVersion(versionPtr); + if (len == -1) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + versionPtr += len; + accLen += len; + assert(accLen < kViEVersionMaxMessageSize); +#endif + + len = AddRtpRtcpModuleVersion(versionPtr); + if (len == -1) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + versionPtr += len; + accLen += len; + assert(accLen < kViEVersionMaxMessageSize); + + len = AddVideoCaptureVersion(versionPtr); + if (len == -1) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + versionPtr += len; + accLen += len; + assert(accLen < kViEVersionMaxMessageSize); + + len = AddRenderVersion(versionPtr); + if (len == -1) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + versionPtr += len; + accLen += len; + assert(accLen < kViEVersionMaxMessageSize); + + len = AddVideoProcessingVersion(versionPtr); + if (len == -1) + { + SetLastError(kViEBaseUnknownError); + return -1; + } + versionPtr += len; + accLen += len; + assert(accLen < kViEVersionMaxMessageSize); + + memcpy(version, versionBuf, accLen); + version[accLen] = '\0'; + + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_instanceId), + "GetVersion() => %s", version); + return 0; +} + +WebRtc_Word32 ViEBaseImpl::AddBuildInfo(char* str) const +{ + return sprintf(str, "Build: %s\n", BUILDINFO); +} + +WebRtc_Word32 ViEBaseImpl::AddViEVersion(char* str) const +{ + return sprintf(str, "VideoEngine 3.1.0\n"); +} + +#ifdef WEBRTC_EXTERNAL_TRANSPORT +WebRtc_Word32 ViEBaseImpl::AddExternalTransportBuild(char* str) const +{ + return sprintf(str, "External transport build\n"); +} +#endif + +WebRtc_Word32 ViEBaseImpl::AddModuleVersion(webrtc::Module* module, + char* str) const +{ + WebRtc_Word8 version[kViEMaxModuleVersionSize]; + WebRtc_UWord32 remainingBufferInBytes(kViEMaxModuleVersionSize); + WebRtc_UWord32 position(0); + if (module && module->Version(version, remainingBufferInBytes, position) + == 0) + { + return sprintf(str, "%s\n", version); + } + return -1; +} + +WebRtc_Word32 ViEBaseImpl::AddVCMVersion(char* str) const +{ + webrtc::VideoCodingModule* vcmPtr = + webrtc::VideoCodingModule::Create(_instanceId); + int len = AddModuleVersion(vcmPtr, str); + webrtc::VideoCodingModule::Destroy(vcmPtr); + return len; +} + +WebRtc_Word32 ViEBaseImpl::AddVideoCaptureVersion(char* str) const +{ + return 0; +} + +WebRtc_Word32 ViEBaseImpl::AddVideoProcessingVersion(char* str) const +{ + webrtc::VideoProcessingModule* videoPtr = + webrtc::VideoProcessingModule::Create(_instanceId); + int len = AddModuleVersion(videoPtr, str); + webrtc::VideoProcessingModule::Destroy(videoPtr); + return len; +} +WebRtc_Word32 ViEBaseImpl::AddRenderVersion(char* str) const +{ + + return 0; +} + +#ifndef WEBRTC_EXTERNAL_TRANSPORT +WebRtc_Word32 ViEBaseImpl::AddSocketModuleVersion(char* str) const +{ + WebRtc_UWord8 numSockThreads(1); + UdpTransport* socketPtr = + UdpTransport::Create( + _instanceId, numSockThreads); + int len = AddModuleVersion(socketPtr, str); + UdpTransport::Destroy(socketPtr); + return len; +} +#endif + +#ifdef WEBRTC_SRTP +WebRtc_Word32 ViEBaseImpl::AddSRTPModuleVersion(char* str) const +{ + SrtpModule* srtpPtr = SrtpModule::CreateSrtpModule(-1); + int len = AddModuleVersion(srtpPtr, str); + SrtpModule::DestroySrtpModule(srtpPtr); + return len; +} +#endif + +WebRtc_Word32 ViEBaseImpl::AddRtpRtcpModuleVersion(char* str) const +{ + RtpRtcp* rtpRtcpPtr = + RtpRtcp::CreateRtpRtcp(-1, true); + int len = AddModuleVersion(rtpRtcpPtr, str); + RtpRtcp::DestroyRtpRtcp(rtpRtcpPtr); + return len; +} + +// ---------------------------------------------------------------------------- +// LastError +// +// Returns the last set error in this ViE instance +// ---------------------------------------------------------------------------- + +int ViEBaseImpl::LastError() +{ + return LastErrorInternal(); +} + +} // namespace webrtc diff --git a/video_engine/main/source/vie_base_impl.h b/video_engine/main/source/vie_base_impl.h new file mode 100644 index 0000000000..1e840dd860 --- /dev/null +++ b/video_engine/main/source/vie_base_impl.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_base_impl.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_BASE_IMPL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_BASE_IMPL_H_ + +#include "vie_defines.h" + +#include "vie_ref_count.h" +#include "vie_shared_data.h" +#include "vie_base.h" + +// Forward declarations +namespace webrtc +{ + +class VoiceEngine; +class Module; +class ViEPerformanceMonitor; + +class ViEBaseImpl: public virtual ViESharedData, + public ViEBase, + public ViERefCount +{ +public: + virtual int Release(); + + virtual int Init(); + + virtual int SetVoiceEngine(VoiceEngine* ptrVoiceEngine); + + // Channel functions + virtual int CreateChannel(int& videoChannel); + + virtual int CreateChannel(int& videoChannel, int originalChannel); + + virtual int DeleteChannel(const int videoChannel); + + virtual int ConnectAudioChannel(const int videoChannel, + const int audioChannel); + + virtual int DisconnectAudioChannel(const int videoChannel); + + // Start and stop + virtual int StartSend(const int videoChannel); + + virtual int StopSend(const int videoChannel); + + virtual int StartReceive(const int videoChannel); + + virtual int StopReceive(const int videoChannel); + + // Callbacks + virtual int RegisterObserver(ViEBaseObserver& observer); + + virtual int DeregisterObserver(); + + // Info functions + virtual int GetVersion(char version[1024]); + + virtual int LastError(); + +protected: + ViEBaseImpl(); + virtual ~ViEBaseImpl(); + ViEPerformanceMonitor _viePerformanceMonitor; +private: + + // Version functions + WebRtc_Word32 AddViEVersion(char* str) const; + WebRtc_Word32 AddBuildInfo(char* str) const; +#ifdef WEBRTC_EXTERNAL_TRANSPORT + WebRtc_Word32 AddExternalTransportBuild(char* str) const; +#else + WebRtc_Word32 AddSocketModuleVersion(char* str) const; +#endif + WebRtc_Word32 AddModuleVersion(webrtc::Module* module, char* str) const; + WebRtc_Word32 AddVCMVersion(char* str) const; + WebRtc_Word32 AddVideoCaptureVersion(char* str) const; + WebRtc_Word32 AddVideoProcessingVersion(char* str) const; + WebRtc_Word32 AddRenderVersion(char* str) const; +#ifdef WEBRTC_SRTP + WebRtc_Word32 AddSRTPModuleVersion(char* str) const; +#endif + WebRtc_Word32 AddRtpRtcpModuleVersion(char* str) const; +}; + +} // namespace webrtc + +#endif // #define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_BASE_IMPL_H_ diff --git a/video_engine/main/source/vie_capture_impl.cc b/video_engine/main/source/vie_capture_impl.cc new file mode 100644 index 0000000000..c1664979c1 --- /dev/null +++ b/video_engine/main/source/vie_capture_impl.cc @@ -0,0 +1,792 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_capture_impl.cc + */ + +#include "vie_capture_impl.h" + +// Defines +#include "vie_defines.h" + +#include "trace.h" +#include "vie_capturer.h" +#include "vie_channel.h" +#include "vie_channel_manager.h" +#include "vie_encoder.h" +#include "vie_impl.h" +#include "vie_input_manager.h" +#include "vie_errors.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// GetInterface +// ---------------------------------------------------------------------------- + +ViECapture* ViECapture::GetInterface(VideoEngine* videoEngine) +{ +#ifdef WEBRTC_VIDEO_ENGINE_CAPTURE_API + if (videoEngine == NULL) + { + return NULL; + } + VideoEngineImpl* vieImpl = reinterpret_cast (videoEngine); + ViECaptureImpl* vieCaptureImpl = vieImpl; + (*vieCaptureImpl)++; // Increase ref count + + return vieCaptureImpl; +#else + return NULL; +#endif +} + +// ---------------------------------------------------------------------------- +// Release +// +// Releases the interface, i.e. reduces the reference counter. The number of +// remaining references is returned, -1 if released too many times. +// ---------------------------------------------------------------------------- + +int ViECaptureImpl::Release() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "ViECapture::Release()"); + (*this)--; // Decrease ref count + + WebRtc_Word32 refCount = GetCount(); + if (refCount < 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, + "ViECapture release too many times"); + SetLastError(kViEAPIDoesNotExist); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId, + "ViECapture reference count: %d", refCount); + return refCount; +} + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViECaptureImpl::ViECaptureImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViECaptureImpl::ViECaptureImpl() Ctor"); +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViECaptureImpl::~ViECaptureImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViECaptureImpl::~ViECaptureImpl() Dtor"); +} + +// ============================================================================ +// Available devices +// ============================================================================ + +// ---------------------------------------------------------------------------- +// NumberOfCaptureDevices +// +// Returns the number of available devices +// ---------------------------------------------------------------------------- +int ViECaptureImpl::NumberOfCaptureDevices() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + return _inputManager.NumberOfCaptureDevices(); +} + +// ---------------------------------------------------------------------------- +// GetCaptureDevice +// +// Gets capture device listNumber, both name and unique id if available +// ---------------------------------------------------------------------------- +int ViECaptureImpl::GetCaptureDevice(unsigned int listNumber, + char* deviceNameUTF8, + unsigned int deviceNameUTF8Length, + char* uniqueIdUTF8, + unsigned int uniqueIdUTF8Length) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(listNumber: %d)", __FUNCTION__, listNumber); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + return _inputManager.GetDeviceName(listNumber, + (WebRtc_UWord8*) deviceNameUTF8, + deviceNameUTF8Length, + (WebRtc_UWord8*) uniqueIdUTF8, + uniqueIdUTF8Length); +} + +// ============================================================================ +// Allocate capture device +// ============================================================================ + + +// ---------------------------------------------------------------------------- +// AllocateCaptureDevice +// +// Allocates the capture device +// ---------------------------------------------------------------------------- +int ViECaptureImpl::AllocateCaptureDevice( + const char* uniqueIdUTF8, + const unsigned int uniqueIdUTF8Length, + int& captureId) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(uniqueIdUTF8: %s)", __FUNCTION__, uniqueIdUTF8); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + const WebRtc_Word32 + result = + _inputManager.CreateCaptureDevice( + (const WebRtc_UWord8*) uniqueIdUTF8, + (const WebRtc_UWord32) uniqueIdUTF8Length, captureId); + if (result != 0) + { + SetLastError(result); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// AllocateExternalCaptureDevice +// +// Register a customer implemented capture device. callback should be called +// for all new captured images once the the capture device is started +// ---------------------------------------------------------------------------- +int ViECaptureImpl::AllocateExternalCaptureDevice( + int& captureId, ViEExternalCapture*& externalCapture) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + const WebRtc_Word32 result = + _inputManager.CreateExternalCaptureDevice(externalCapture, captureId); + + if (result != 0) + { + SetLastError(result); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// AllocateCaptureDevice +// +// Allocates the capture device, the capture module to attach +// must be associated with the unique ID. +// ---------------------------------------------------------------------------- +int ViECaptureImpl::AllocateCaptureDevice(VideoCaptureModule& captureModule, + int& captureId) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + const WebRtc_Word32 result = + _inputManager.CreateCaptureDevice(captureModule, captureId); + if (result != 0) + { + SetLastError(result); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// ReleaseCaptureDevice +// +// Releases an allocated capture device +// ---------------------------------------------------------------------------- +int ViECaptureImpl::ReleaseCaptureDevice(const int captureId) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(captureId: %d)", __FUNCTION__, captureId); + + { + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrViECapture = is.Capture(captureId); + if (ptrViECapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViECaptureDeviceDoesnNotExist); + return -1; + } + + } + + // Destroy the capture device + return _inputManager.DestroyCaptureDevice(captureId); +} + +// ============================================================================ +// Pair capture device and channel +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ConnectCaptureDevice +// +// Connects a capture device with a channel, i.e. the capture video from this +// device will be sent to that channel. Serveral channels can be connectet to +// the same capture device. +// ---------------------------------------------------------------------------- +int ViECaptureImpl::ConnectCaptureDevice(const int captureId, + const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(captureId: %d, videoChannel: %d)", __FUNCTION__, captureId, + videoChannel); + + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrViECapture = is.Capture(captureId); + if (ptrViECapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViECaptureDeviceDoesnNotExist); + return -1; + } + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel); + if (ptrViEEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViECaptureDeviceInvalidChannelId); + return -1; + } + // Check if the encoder already has a connected frame provider + if (is.FrameProvider(ptrViEEncoder) != NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d already connected to a capture device.", + __FUNCTION__, videoChannel); + SetLastError(kViECaptureDeviceAlreadyConnected); + return -1; + } + VideoCodec codec; + bool useHardwareEncoder = false; + if (ptrViEEncoder->GetEncoder(codec) == 0) + { // try to provide the encoder with preencoded frames if possible + if (ptrViECapture->PreEncodeToViEEncoder(codec, *ptrViEEncoder, + videoChannel) == 0) + { + useHardwareEncoder = true; + } + } + // If we don't use the camera as hardware encoder we register the vieEncoder + // for callbacks + if (!useHardwareEncoder + && ptrViECapture->RegisterFrameCallback(videoChannel, ptrViEEncoder) + != 0) + { + SetLastError(kViECaptureDeviceUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DisconnectCaptureDevice +// +// Disconnects a capture device from a connected channel. +// ---------------------------------------------------------------------------- +int ViECaptureImpl::DisconnectCaptureDevice(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel); + if (ptrViEEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViECaptureDeviceInvalidChannelId); + return -1; + } + + ViEInputManagerScoped is(_inputManager); + ViEFrameProviderBase* frameProvider = is.FrameProvider(ptrViEEncoder); + if (!frameProvider) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: No capture device connected to channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECaptureDeviceNotConnected); + return -1; + } + if (frameProvider->Id() < kViECaptureIdBase + || frameProvider->Id() > kViECaptureIdMax) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: No capture device connected to channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECaptureDeviceNotConnected); + return -1; + } + + if (frameProvider->DeregisterFrameCallback(ptrViEEncoder) != 0) + { + SetLastError(kViECaptureDeviceUnknownError); + return -1; + } + + return 0; + +} + +// ============================================================================ +// Start/stop +// ============================================================================ + +// ---------------------------------------------------------------------------- +// StartCapture +// +// Starts an allocated capture device, i.e. will start output captured frame +// ---------------------------------------------------------------------------- +int ViECaptureImpl::StartCapture(const int captureId, + const CaptureCapability captureCapability) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(captureId: %d)", __FUNCTION__, captureId); + + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrViECapture = is.Capture(captureId); + if (ptrViECapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, captureId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViECaptureDeviceDoesnNotExist); + return -1; + } + if (ptrViECapture->Started()) + { + SetLastError(kViECaptureDeviceAlreadyStarted); + return -1; + } + if (ptrViECapture->Start(captureCapability) != 0) + { + SetLastError(kViECaptureDeviceUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// StopCapture +// +// Stops a started capture device +// ---------------------------------------------------------------------------- +int ViECaptureImpl::StopCapture(const int captureId) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(captureId: %d)", __FUNCTION__, captureId); + + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrViECapture = is.Capture(captureId); + if (ptrViECapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, captureId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViECaptureDeviceDoesnNotExist); + return -1; + } + if (!ptrViECapture->Started()) + { + SetLastError(kViECaptureDeviceNotStarted); + return -1; + } + if (ptrViECapture->Stop() != 0) + { + SetLastError(kViECaptureDeviceUnknownError); + return -1; + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// RotateCapturedFrames +// +// Rotates a frame as soon as it's delivered from the capture device. +// This will apply to mobile devices with accelerometers or other rotation +// detection abilities. +// ---------------------------------------------------------------------------- +int ViECaptureImpl::SetRotateCapturedFrames(const int captureId, + const RotateCapturedFrame rotation) +{ + int iRotation = -1; + switch (rotation) + { + case RotateCapturedFrame_0: + iRotation = 0; + break; + case RotateCapturedFrame_90: + iRotation = 90; + break; + case RotateCapturedFrame_180: + iRotation = 180; + break; + case RotateCapturedFrame_270: + iRotation = 270; + break; + + } + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(rotation: %d)", __FUNCTION__, iRotation); + + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrViECapture = is.Capture(captureId); + if (ptrViECapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, captureId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViECaptureDeviceDoesnNotExist); + return -1; + } + if (ptrViECapture->SetRotateCapturedFrames(rotation) != 0) + { + SetLastError(kViECaptureDeviceUnknownError); + return -1; + } + + return 0; + +} + +// ---------------------------------------------------------------------------- +// SetCaptureDelay +// +// Defines the capture delay for an external capture device. +// This call will also override a the capture delay value for a capture +// device. +// ---------------------------------------------------------------------------- +int ViECaptureImpl::SetCaptureDelay(const int captureId, + const unsigned int captureDelayMs) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(captureId: %d, captureDelayMs %u)", __FUNCTION__, + captureId, captureDelayMs); + + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrViECapture = is.Capture(captureId); + if (ptrViECapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, captureId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViECaptureDeviceDoesnNotExist); + return -1; + } + + if (ptrViECapture->SetCaptureDelay(captureDelayMs) != 0) + { + SetLastError(kViECaptureDeviceUnknownError); + return -1; + } + return 0; + +} + +// ============================================================================ +// Capture capabilities +// ============================================================================ + +// ---------------------------------------------------------------------------- +// NumberOfCapabilities +// +// Returns the number of capabilities fot the specified device +// ---------------------------------------------------------------------------- +int ViECaptureImpl::NumberOfCapabilities(const char* uniqueIdUTF8, + const unsigned int uniqueIdUTF8Length) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(captureDeviceName: %s)", __FUNCTION__, uniqueIdUTF8); + +#if defined(WEBRTC_MAC_INTEL) + // TODO: Move to capture module! + // QTKit framework handles all capabilites and capture settings + // automatically (mandatory). + // Thus this function cannot be supported on the Mac platform. + SetLastError(kViECaptureDeviceMacQtkitNotSupported); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s This API is not supported on Mac OS", __FUNCTION__, + _instanceId); + return -1; +#endif + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + return (int) _inputManager.NumberOfCaptureCapabilities( + (WebRtc_UWord8*) uniqueIdUTF8); +} + +// ---------------------------------------------------------------------------- +// GetCaptureCapability +// +// Gets a capture capability for the specified capture device +// ---------------------------------------------------------------------------- +int ViECaptureImpl::GetCaptureCapability(const char* uniqueIdUTF8, + const unsigned int uniqueIdUTF8Length, + const unsigned int capabilityNumber, + CaptureCapability& capability) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(captureDeviceName: %s)", __FUNCTION__, uniqueIdUTF8); + +#if defined(WEBRTC_MAC_INTEL) + // TODO: Move to capture module! + // QTKit framework handles all capabilites and capture settings + // automatically (mandatory). + // Thus this function cannot be supported on the Mac platform. + SetLastError(kViECaptureDeviceMacQtkitNotSupported); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s This API is not supported on Mac OS", __FUNCTION__, + _instanceId); + return -1; +#endif + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + if (_inputManager.GetCaptureCapability((WebRtc_UWord8*) uniqueIdUTF8, + capabilityNumber, capability) != 0) + { + SetLastError(kViECaptureDeviceUnknownError); + return -1; + } + return 0; +} + +int ViECaptureImpl::ShowCaptureSettingsDialogBox( + const char* uniqueIdUTF8, const unsigned int uniqueIdUTF8Length, + const char* dialogTitle, void* parentWindow /*= NULL*/, + const unsigned int x/*=200*/, const unsigned int y/*=200*/) +{ +#if defined(WEBRTC_MAC_INTEL) + // TODO: Move to capture module + // QTKit framework handles all capabilites and capture settings + // automatically (mandatory). + // Thus this function cannot be supported on the Mac platform. + SetLastError(kViECaptureDeviceMacQtkitNotSupported); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s This API is not supported on Mac OS", __FUNCTION__, + _instanceId); + return -1; +#endif + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s captureId (captureDeviceName: %s)", __FUNCTION__, + uniqueIdUTF8); + + return _inputManager.DisplayCaptureSettingsDialogBox( + (WebRtc_UWord8*) uniqueIdUTF8, (WebRtc_UWord8*) dialogTitle, + parentWindow, x, y); +} + +int ViECaptureImpl::GetOrientation(const char* uniqueIdUTF8, + RotateCapturedFrame &orientation) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s (captureDeviceName: %s)", __FUNCTION__, uniqueIdUTF8); + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + if (_inputManager.GetOrientation((WebRtc_UWord8*) uniqueIdUTF8, + orientation) != 0) + { + SetLastError(kViECaptureDeviceUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// Callbacks +// ============================================================================ + +// ---------------------------------------------------------------------------- +// EnableBrightnessAlarm +// +// Enables brightness alarm callback for a specified capture device +// ---------------------------------------------------------------------------- +int ViECaptureImpl::EnableBrightnessAlarm(const int captureId, + const bool enable) +{ + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrViECapture = is.Capture(captureId); + if (ptrViECapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, captureId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViECaptureDeviceDoesnNotExist); + return -1; + } + if (ptrViECapture->EnableBrightnessAlarm(enable) != 0) + { + SetLastError(kViECaptureDeviceUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterObserver +// +// Register the customer implemented observer for capture callbacks +// ---------------------------------------------------------------------------- +int ViECaptureImpl::RegisterObserver(const int captureId, + ViECaptureObserver& observer) +{ + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrViECapture = is.Capture(captureId); + if (ptrViECapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, captureId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViECaptureDeviceDoesnNotExist); + return -1; + } + if (ptrViECapture->IsObserverRegistered()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, captureId), + "%s: Observer already registered", __FUNCTION__); + SetLastError(kViECaptureObserverAlreadyRegistered); + return -1; + } + + if (ptrViECapture->RegisterObserver(observer) != 0) + { + SetLastError(kViECaptureDeviceUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterObserver +// +// Removes the previously registered observer +// ---------------------------------------------------------------------------- +int ViECaptureImpl::DeregisterObserver(const int captureId) +{ + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrViECapture = is.Capture(captureId); + if (ptrViECapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, captureId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViECaptureDeviceDoesnNotExist); + return -1; + } + if (!ptrViECapture->IsObserverRegistered()) + { + SetLastError(kViECaptureDeviceObserverNotRegistered); + return -1; + } + + if (ptrViECapture->DeRegisterObserver() != 0) + { + SetLastError(kViECaptureDeviceUnknownError); + return -1; + } + return 0; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_capture_impl.h b/video_engine/main/source/vie_capture_impl.h new file mode 100644 index 0000000000..4434aaa14a --- /dev/null +++ b/video_engine/main/source/vie_capture_impl.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_capture_impl.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CAPTURE_IMPL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CAPTURE_IMPL_H_ + +#include "vie_defines.h" + +#include "typedefs.h" +#include "vie_capture.h" +#include "vie_ref_count.h" +#include "vie_shared_data.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// ViECaptureImpl +// ---------------------------------------------------------------------------- + +class ViECaptureImpl: public virtual ViESharedData, + public ViECapture, + public ViERefCount +{ +public: + virtual int Release(); + + // Available devices + virtual int NumberOfCaptureDevices(); + + virtual int GetCaptureDevice(unsigned int listNumber, char* deviceNameUTF8, + const unsigned int deviceNameUTF8Length, + char* uniqueIdUTF8, + const unsigned int uniqueIdUTF8Length); + + // Allocate capture device + virtual int AllocateCaptureDevice(const char* uniqueIdUTF8, + const unsigned int uniqueIdUTF8Length, + int& captureId); + + // Allocate capture device + virtual int AllocateCaptureDevice(VideoCaptureModule& captureModule, + int& captureId); + // Allocate external capture device + virtual int AllocateExternalCaptureDevice( + int& captureId, ViEExternalCapture *&externalCapture); + + virtual int ReleaseCaptureDevice(const int captureId); + + // Pair capture device and channel + virtual int ConnectCaptureDevice(const int captureId, + const int videoChannel); + + virtual int DisconnectCaptureDevice(const int videoChannel); + + // Start/stop + virtual int StartCapture(const int captureId, + const CaptureCapability captureCapability = + CaptureCapability()); + + virtual int StopCapture(const int captureId); + + virtual int SetRotateCapturedFrames(const int captureId, + const RotateCapturedFrame rotation); + + virtual int SetCaptureDelay(const int captureId, + const unsigned int captureDelayMs); + + // Capture capabilities + virtual int NumberOfCapabilities(const char* uniqueIdUTF8, + const unsigned int uniqueIdUTF8Length); + + virtual int GetCaptureCapability(const char* uniqueIdUTF8, + const unsigned int uniqueIdUTF8Length, + const unsigned int capabilityNumber, + CaptureCapability& capability); + + virtual int ShowCaptureSettingsDialogBox( + const char* uniqueIdUTF8, const unsigned int uniqueIdUTF8Length, + const char* dialogTitle, void* parentWindow = NULL, + const unsigned int x = 200, const unsigned int y = 200); + + virtual int GetOrientation(const char* uniqueIdUTF8, + RotateCapturedFrame &orientation); + + // Callbacks + virtual int EnableBrightnessAlarm(const int captureId, const bool enable); + + virtual int RegisterObserver(const int captureId, + ViECaptureObserver& observer); + + virtual int DeregisterObserver(const int captureId); + +protected: + ViECaptureImpl(); + virtual ~ViECaptureImpl(); +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CAPTURE_IMPL_H_ diff --git a/video_engine/main/source/vie_capturer.cc b/video_engine/main/source/vie_capturer.cc new file mode 100644 index 0000000000..ea5afd491f --- /dev/null +++ b/video_engine/main/source/vie_capturer.cc @@ -0,0 +1,1092 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_capturer.cc + */ + +#include "vie_capturer.h" +#include "vie_defines.h" + +#include "critical_section_wrapper.h" +#include "event_wrapper.h" +#include "module_common_types.h" +#include "video_capture.h" +#include "video_capture.h" +#include "video_processing.h" +#include "video_render_defines.h" +#include "thread_wrapper.h" +#include "vie_image_process.h" +#include "vie_encoder.h" +#include "process_thread.h" +#include "trace.h" + +namespace webrtc { + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViECapturer::ViECapturer(int captureId, + int engineId, + ProcessThread& moduleProcessThread) + : ViEFrameProviderBase(captureId, engineId), + _captureCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _deliverCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _captureModule(NULL), _useExternalModule(false), + _externalCaptureModule(NULL), + _moduleProcessThread(moduleProcessThread), + _captureId(captureId), + _vieCaptureThread(*ThreadWrapper::CreateThread(ViECaptureThreadFunction, + this, kHighPriority, + "ViECaptureThread")), + _vieCaptureEvent(*EventWrapper::Create()), + _vieDeliverEvent(*EventWrapper::Create()), _capturedFrame(), + _deliverFrame(), + _observerCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _observer(NULL), _effectFilter(NULL), _imageProcModule(NULL), + _imageProcModuleRefCounter(0), _deflickerFrameStats(NULL), + _brightnessFrameStats(NULL), _currentBrightnessLevel(Normal), + _reportedBrightnessLevel(Normal), _denoisingEnabled(false), + _encodingCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _captureEncoder(NULL), _encodeCompleteCallback(NULL), + _vieEncoder(NULL), _vcm(NULL), _decodeBuffer(), + _decoderInitialized(false), _requestedCapability() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(engineId, captureId), + "ViECapturer::ViECapturer(captureId: %d, engineId: %d) - " + "Constructor", captureId, engineId); + + unsigned int tId = 0; + if (_vieCaptureThread.Start(tId)) + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(engineId, captureId), + "%s: thread started: %u", __FUNCTION__, tId); + } else + { + assert(false); + } +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViECapturer::~ViECapturer() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, + ViEId(_engineId, _captureId), + "ViECapturer Destructor, captureId: %d, engineId: %d", + _captureId, _engineId); + + // Stop the thread + _deliverCritsect.Enter(); + _captureCritsect.Enter(); + _vieCaptureThread.SetNotAlive(); + _vieCaptureEvent.Set(); + _captureCritsect.Leave(); + _deliverCritsect.Leave(); + + _providerCritSect.Enter(); + if (_vieEncoder) + { + _vieEncoder->DeRegisterExternalEncoder(_codec.plType); + } + _providerCritSect.Leave(); + + // Stop the camera input + if (_captureModule) + { + _moduleProcessThread.DeRegisterModule(_captureModule); + _captureModule->DeRegisterCaptureDataCallback(); + } + if (_vieCaptureThread.Stop()) + { + // Thread stopped + delete &_vieCaptureThread; + delete &_vieCaptureEvent; + delete &_vieDeliverEvent; + } else + { + assert(false); + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideoRenderer, ViEId(_engineId, _captureId), + "%s: Not able to stop capture thread for device %d, leaking", + __FUNCTION__, _captureId); + // Not possible to stop the thread, leak it... + } + + if (!_useExternalModule) + { + VideoCaptureModule::Destroy(_captureModule); + } + _captureModule = NULL; + if (_imageProcModule) + { + VideoProcessingModule::Destroy(_imageProcModule); + } + if (_deflickerFrameStats) + { + delete _deflickerFrameStats; + _deflickerFrameStats = NULL; + } + delete _brightnessFrameStats; + if (_vcm) + { + delete _vcm; + } + delete &_captureCritsect; + delete &_deliverCritsect; + delete &_encodingCritsect; + delete &_observerCritsect; +} + +// ---------------------------------------------------------------------------- +// Static factory class +// ---------------------------------------------------------------------------- +ViECapturer* ViECapturer::CreateViECapture(int captureId, + int engineId, + VideoCaptureModule& captureModule, + ProcessThread& moduleProcessThread) +{ + ViECapturer* capture = new ViECapturer(captureId, engineId, + moduleProcessThread); + if (!capture || capture->Init(captureModule) != 0) + { + delete capture; + capture = NULL; + } + return capture; +} + +WebRtc_Word32 ViECapturer::Init(VideoCaptureModule& captureModule) +{ + _captureModule = &captureModule; + _useExternalModule = true; + _captureModule->RegisterCaptureDataCallback(*this); + if (_moduleProcessThread.RegisterModule(_captureModule) != 0) + { + return -1; + } + return 0; +} + +ViECapturer* ViECapturer::CreateViECapture(int captureId, + int engineId, + const WebRtc_UWord8* deviceUniqueIdUTF8, + const WebRtc_UWord32 deviceUniqueIdUTF8Length, + ProcessThread& moduleProcessThread) +{ + ViECapturer* capture = new ViECapturer(captureId, engineId, moduleProcessThread); + if (!capture || + capture->Init(deviceUniqueIdUTF8, deviceUniqueIdUTF8Length) != 0) + { + delete capture; + capture = NULL; + } + return capture; +} +WebRtc_Word32 ViECapturer::Init(const WebRtc_UWord8* deviceUniqueIdUTF8, + const WebRtc_UWord32 deviceUniqueIdUTF8Length) +{ +#ifndef WEBRTC_VIDEO_EXTERNAL_CAPTURE_AND_RENDER + if (deviceUniqueIdUTF8 == NULL) + { + _captureModule = VideoCaptureModule::Create( + ViEModuleId(_engineId, _captureId), + _externalCaptureModule); + } else + { + _captureModule = VideoCaptureModule::Create( + ViEModuleId(_engineId, _captureId), + deviceUniqueIdUTF8); + } +#endif + if (!_captureModule) + return -1; + _captureModule->RegisterCaptureDataCallback(*this); + if (_moduleProcessThread.RegisterModule(_captureModule) != 0) + { + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// FrameCallbackChanged +// ---------------------------------------------------------------------------- +int ViECapturer::FrameCallbackChanged() +{ + if (Started() && !EncoderActive() && !CaptureCapabilityFixed()) // Reconfigure the camera if a new size is required and the capture device does not provide encoded frames. + { + int bestWidth; + int bestHeight; + int bestFrameRate; + VideoCaptureCapability captureSettings; + _captureModule->CaptureSettings(captureSettings); + GetBestFormat(bestWidth, bestHeight, bestFrameRate); + if (bestWidth != 0 && bestHeight != 0 && bestFrameRate != 0) + { + if (bestWidth != captureSettings.width || + bestHeight != captureSettings.height || + bestFrameRate != captureSettings.maxFPS || + captureSettings.codecType != kVideoCodecUnknown) + { + Stop(); + Start(_requestedCapability); + } + } + } + return 0; +} + +// ---------------------------------------------------------------------------- +// Start +// +// Starts the capture device. +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViECapturer::Start(const CaptureCapability captureCapability) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s", __FUNCTION__); + + int width; + int height; + int frameRate; + VideoCaptureCapability capability; + _requestedCapability = captureCapability; + if (EncoderActive()) + { + CriticalSectionScoped cs(_encodingCritsect); + capability.width = _codec.width; + capability.height = _codec.height; + capability.maxFPS = _codec.maxFramerate; + capability.codecType = _codec.codecType; + capability.rawType = kVideoI420; + + } else if (!CaptureCapabilityFixed()) + { + GetBestFormat(width, height, frameRate); // Ask the observers for best size + if (width == 0) + { + width = kViECaptureDefaultWidth; + } + if (height == 0) + { + height = kViECaptureDefaultHeight; + } + if (frameRate == 0) + { + frameRate = kViECaptureDefaultFramerate; + } + capability.height = height; + capability.width = width; + capability.maxFPS = frameRate; + capability.rawType = kVideoI420; + capability.codecType = kVideoCodecUnknown; + } else // Width and heigh and type specified with call to Start - not set by observers. + { + capability.width = _requestedCapability.width; + capability.height = _requestedCapability.height; + capability.maxFPS = _requestedCapability.maxFPS; + capability.rawType = _requestedCapability.rawType; + capability.interlaced = _requestedCapability.interlaced; + } + return _captureModule->StartCapture(capability); +} + +// ---------------------------------------------------------------------------- +// Stop +// +// Stops the capture device +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViECapturer::Stop() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s", __FUNCTION__); + _requestedCapability = CaptureCapability(); + return _captureModule->StopCapture(); +} + +// ---------------------------------------------------------------------------- +// Started +// +// Returns true if the capture device is started, false otherwise +// ---------------------------------------------------------------------------- + +bool ViECapturer::Started() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s", __FUNCTION__); + return _captureModule->CaptureStarted(); +} + +const WebRtc_UWord8* ViECapturer::CurrentDeviceName() const +{ + return _captureModule->CurrentDeviceName(); +} + +// ---------------------------------------------------------------------------- +// SetCaptureDelay +// +// Overrides the capture delay +// ---------------------------------------------------------------------------- +WebRtc_Word32 ViECapturer::SetCaptureDelay(WebRtc_Word32 delayMs) +{ + return _captureModule->SetCaptureDelay(delayMs); +} + +// ---------------------------------------------------------------------------- +// SetCapturedFrameRotation +// +// Tell the capture module whether or not to rotate a frame when it is captured +// ---------------------------------------------------------------------------- +WebRtc_Word32 ViECapturer::SetRotateCapturedFrames( + const RotateCapturedFrame rotation) +{ + VideoCaptureRotation convertedRotation = kCameraRotate0; + switch (rotation) + { + case RotateCapturedFrame_0: + convertedRotation = kCameraRotate0; + break; + case RotateCapturedFrame_90: + convertedRotation = kCameraRotate90; + break; + case RotateCapturedFrame_180: + convertedRotation = kCameraRotate180; + break; + case RotateCapturedFrame_270: + convertedRotation = kCameraRotate270; + break; + default: + break; + } + return _captureModule->SetCaptureRotation(convertedRotation); +} + +// ---------------------------------------------------------------------------- +// IncomingFrame +// +// Inherited from ExternalCapture, will deliver a new captured +// frame to the capture module. +// ---------------------------------------------------------------------------- + +int ViECapturer::IncomingFrame(unsigned char* videoFrame, + unsigned int videoFrameLength, + unsigned short width, unsigned short height, + RawVideoType videoType, + unsigned long long captureTime) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%ExternalCapture::IncomingFrame width %d, height %d, captureTime %u", + width, height, captureTime); + + if (!_externalCaptureModule) + { + return -1; + } + VideoCaptureCapability capability; + capability.width = width; + capability.height = height; + capability.rawType = videoType; + return _externalCaptureModule->IncomingFrame(videoFrame, videoFrameLength, + capability, captureTime); +} +// ---------------------------------------------------------------------------- +// OnIncomingCapturedFrame +// +// Inherited from VideoCaptureDataCallback, will deliver a new captured +// frame +// ---------------------------------------------------------------------------- + +void ViECapturer::OnIncomingCapturedFrame(const WebRtc_Word32 captureId, + VideoFrame& videoFrame, + VideoCodecType codecType) +{ + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureId: %d)", __FUNCTION__, captureId); + + CriticalSectionScoped cs(_captureCritsect); + if (codecType != kVideoCodecUnknown) + { + if (_encodedFrame.Length() != 0) // The last encoded frame has not been sent yet. Need to wait + { + _vieDeliverEvent.Reset(); + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureId: %d) Last encoded frame not yet delivered.", + __FUNCTION__, captureId); + _captureCritsect.Leave(); + _vieDeliverEvent.Wait(500); // Wait 500ms for the coded frame to be sent before unblocking this. + assert(_encodedFrame.Length()==0); + _captureCritsect.Enter(); + } + _encodedFrame.SwapFrame(videoFrame); + } else + { + _capturedFrame.SwapFrame(videoFrame); + } + _vieCaptureEvent.Set(); + return; +} + +void ViECapturer::OnCaptureDelayChanged(const WebRtc_Word32 id, + const WebRtc_Word32 delay) +{ + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, + ViEId(_engineId, _captureId), + "%s(captureId: %d) delay %d", __FUNCTION__, _captureId, + delay); + + // Deliver the network delay to all registered callbacks + ViEFrameProviderBase::SetFrameDelay(delay); + CriticalSectionScoped cs(_encodingCritsect); + if (_vieEncoder) + { + _vieEncoder->DelayChanged(id, delay); + } +} + +WebRtc_Word32 ViECapturer::RegisterEffectFilter(ViEEffectFilter* effectFilter) +{ + CriticalSectionScoped cs(_deliverCritsect); + + if (effectFilter == NULL) + { + if (_effectFilter == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s: no effect filter added for capture device %d", + __FUNCTION__, _captureId); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId,_captureId), + "%s: deregister effect filter for device %d", __FUNCTION__, + _captureId); + } else + { + if (_effectFilter) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId,_captureId), + "%s: effect filter already added for capture device %d", + __FUNCTION__, _captureId); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s: register effect filter for device %d", __FUNCTION__, + _captureId); + } + _effectFilter = effectFilter; + return 0; +} + +//------------------------------------------------------------------------------------------------ +// +// IncImageProcRefCount +// Help function used for keeping track of VideoImageProcesingModule. Creates the module if it is needed. +// Return 0 on success and guarantee that the image proc module exist. +//------------------------------------------------------------------------------------------------ + +WebRtc_Word32 ViECapturer::IncImageProcRefCount() +{ + if (!_imageProcModule) + { + assert(_imageProcModuleRefCounter==0); + _imageProcModule = VideoProcessingModule::Create(ViEModuleId(_engineId, _captureId)); + if (_imageProcModule == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s: could not create video processing module", + __FUNCTION__); + return -1; + } + } + _imageProcModuleRefCounter++; + return 0; +} +WebRtc_Word32 ViECapturer::DecImageProcRefCount() +{ + _imageProcModuleRefCounter--; + // Destroy module + if (_imageProcModuleRefCounter == 0) + { + VideoProcessingModule::Destroy(_imageProcModule); + _imageProcModule = NULL; + } + return 0; +} + +WebRtc_Word32 ViECapturer::EnableDenoising(bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d, enable: %d)", __FUNCTION__, + _captureId, enable); + + CriticalSectionScoped cs(_deliverCritsect); + if (enable) + { + // Sanity check + if (_denoisingEnabled) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s: denoising already enabled", __FUNCTION__); + return -1; + } + _denoisingEnabled = true; + if (IncImageProcRefCount() != 0) + { + return -1; + } + } else + { + // Sanity check + if (_denoisingEnabled == false) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s: denoising not enabled", __FUNCTION__); + return -1; + } + _denoisingEnabled = false; + DecImageProcRefCount(); + } + + return 0; +} + +WebRtc_Word32 ViECapturer::EnableDeflickering(bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d, enable: %d)", __FUNCTION__, + _captureId, enable); + + CriticalSectionScoped cs(_deliverCritsect); + if (enable) + { + // Sanity check + if (_deflickerFrameStats) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s: deflickering already enabled", __FUNCTION__); + return -1; + } + // Create the module + if (IncImageProcRefCount() != 0) + { + return -1; + } + _deflickerFrameStats = new VideoProcessingModule::FrameStats(); + } else + { + // Sanity check + if (_deflickerFrameStats == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s: deflickering not enabled", __FUNCTION__); + return -1; + } + // Destroy module + DecImageProcRefCount(); + delete _deflickerFrameStats; + _deflickerFrameStats = NULL; + } + return 0; +} +WebRtc_Word32 ViECapturer::EnableBrightnessAlarm(bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d, enable: %d)", __FUNCTION__, + _captureId, enable); + + CriticalSectionScoped cs(_deliverCritsect); + if (enable) + { + // Sanity check + if (_brightnessFrameStats) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s: BrightnessAlarm already enabled", __FUNCTION__); + return -1; + } + if (IncImageProcRefCount() != 0) + { + return -1; + } + _brightnessFrameStats = new VideoProcessingModule::FrameStats(); + } else + { + DecImageProcRefCount(); + // Sanity check + if (_brightnessFrameStats == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s: deflickering not enabled", __FUNCTION__); + return -1; + } + delete _brightnessFrameStats; + _brightnessFrameStats = NULL; + } + return 0; +} + +bool ViECapturer::ViECaptureThreadFunction(void* obj) +{ + return static_cast (obj)->ViECaptureProcess(); +} + +bool ViECapturer::ViECaptureProcess() +{ + if (_vieCaptureEvent.Wait(kThreadWaitTimeMs) == kEventSignaled) + { + _deliverCritsect.Enter(); + if (_capturedFrame.Length() > 0) // New I420 frame + { + _captureCritsect.Enter(); + _deliverFrame.SwapFrame(_capturedFrame); + _capturedFrame.SetLength(0); + _captureCritsect.Leave(); + DeliverI420Frame(_deliverFrame); + } + if (_encodedFrame.Length() > 0) + { + _captureCritsect.Enter(); + _deliverFrame.SwapFrame(_encodedFrame); + _encodedFrame.SetLength(0); + _vieDeliverEvent.Set(); + _captureCritsect.Leave(); + DeliverCodedFrame(_deliverFrame); + } + _deliverCritsect.Leave(); + if (_currentBrightnessLevel != _reportedBrightnessLevel) + { + CriticalSectionScoped cs(_observerCritsect); + if (_observer) + { + _observer->BrightnessAlarm(_id, _currentBrightnessLevel); + _reportedBrightnessLevel = _currentBrightnessLevel; + } + } + } + // We're done! + return true; +} + +void ViECapturer::DeliverI420Frame(VideoFrame& videoFrame) +{ + // Apply image enhancement and effect filter + if (_deflickerFrameStats) + { + if (_imageProcModule->GetFrameStats(*_deflickerFrameStats, videoFrame) == 0) + { + _imageProcModule->Deflickering(videoFrame, *_deflickerFrameStats); + } else + { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s: could not get frame stats for captured frame", __FUNCTION__); + } + } + if (_denoisingEnabled) + { + _imageProcModule->Denoising(videoFrame); + } + if (_brightnessFrameStats) + { + if (_imageProcModule->GetFrameStats (*_brightnessFrameStats, videoFrame) == 0) + { + WebRtc_Word32 brightness = _imageProcModule->BrightnessDetection( + videoFrame, + *_brightnessFrameStats); + switch (brightness) + { + case VideoProcessingModule::kNoWarning: + _currentBrightnessLevel = Normal; + break; + case VideoProcessingModule::kDarkWarning: + _currentBrightnessLevel = Dark; + break; + case VideoProcessingModule::kBrightWarning: + _currentBrightnessLevel = Bright; + break; + default: + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _captureId), + "%s: Brightness detection failed", __FUNCTION__); + } + } + } + if (_effectFilter) + { + _effectFilter->Transform(videoFrame.Length(), videoFrame.Buffer(), + videoFrame.TimeStamp(), videoFrame.Width(), + videoFrame.Height()); + } + // Deliver the captured frame to all observers (channels,renderer or file) + ViEFrameProviderBase::DeliverFrame(videoFrame); +} + +void ViECapturer::DeliverCodedFrame(VideoFrame& videoFrame) +{ + if (_encodeCompleteCallback) + { + EncodedImage encodedImage(videoFrame.Buffer(), + videoFrame.Length(), + videoFrame.Size()); + encodedImage._timeStamp = 90*(WebRtc_UWord32) videoFrame.RenderTimeMs(); + _encodeCompleteCallback->Encoded(encodedImage); + } + + if (NumberOfRegistersFrameCallbacks() > 0 && _decoderInitialized) + { + videoFrame.Swap(_decodeBuffer.payloadData, _decodeBuffer.bufferSize, + _decodeBuffer.payloadSize); + _decodeBuffer.encodedHeight = videoFrame.Height(); + _decodeBuffer.encodedWidth = videoFrame.Width(); + _decodeBuffer.renderTimeMs = videoFrame.RenderTimeMs(); + _decodeBuffer.timeStamp = 90*(WebRtc_UWord32) videoFrame.RenderTimeMs(); + _decodeBuffer.payloadType = _codec.plType; + _vcm->DecodeFromStorage(_decodeBuffer); + } + +} +/* + * DeregisterFrameCallback - Overrides ViEFrameProvider + */ +int ViECapturer::DeregisterFrameCallback(const ViEFrameCallback* callbackObject) +{ + + _providerCritSect.Enter(); + if (callbackObject == _vieEncoder) //Don't use this camera as encoder anymore. Need to tell the ViEEncoder. + { + ViEEncoder* vieEncoder = NULL; + vieEncoder = _vieEncoder; + _vieEncoder = NULL; + _providerCritSect.Leave(); + _deliverCritsect.Enter(); //Need to take this here in order to avoid deadlock with VCM. The reason is that VCM will call ::Release and a deadlock can occure. + vieEncoder->DeRegisterExternalEncoder(_codec.plType); + _deliverCritsect.Leave(); + return 0; + } + _providerCritSect.Leave(); + return ViEFrameProviderBase::DeregisterFrameCallback(callbackObject); +} + +/* + * IsFrameCallbackRegistered - Overrides ViEFrameProvider + */ +bool ViECapturer::IsFrameCallbackRegistered(const ViEFrameCallback* callbackObject) +{ + CriticalSectionScoped cs(_providerCritSect); + if (callbackObject == _vieEncoder) + { + return true; + } + return ViEFrameProviderBase::IsFrameCallbackRegistered(callbackObject); + +} + +// ---------------------------------------------------------------------------- +// External encoder using attached capture device. +// Implements VideoEncoderInterface +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViECapturer::PreEncodeToViEEncoder(const VideoCodec& codec, + ViEEncoder& vieEncoder, + WebRtc_Word32 vieEncoderId) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d)", __FUNCTION__, _captureId); + { + if (_vieEncoder && &vieEncoder != _vieEncoder) + { + WEBRTC_TRACE( webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d Capture device already encoding)", + __FUNCTION__, _captureId); + return -1; + } + } + CriticalSectionScoped cs(_encodingCritsect); + VideoCaptureModule::VideoCaptureEncodeInterface* captureEncoder = + _captureModule->GetEncodeInterface(codec); + if (!captureEncoder) + return -1; // Encoding not supported? + + _captureEncoder = captureEncoder; + // Create VCM module used for decoding frames if needed. + if (!_vcm) + { + _vcm = VideoCodingModule::Create(_captureId); + } + + if (vieEncoder.RegisterExternalEncoder(this, codec.plType) != 0) + { + return -1; + } + if (vieEncoder.SetEncoder(codec) != 0) + { + vieEncoder.DeRegisterExternalEncoder(codec.plType); + return -1; + } + // Make sure the encoder is not an I420 observer. + ViEFrameProviderBase::DeregisterFrameCallback(&vieEncoder); + _vieEncoder = &vieEncoder; // Store the vieEncoder that is using this capture device. + _vieEncoderId = vieEncoderId; + memcpy(&_codec, &codec, sizeof(webrtc::VideoCodec)); + return 0; +} + +bool ViECapturer::EncoderActive() +{ + return _vieEncoder != NULL; +} + +/* + * CaptureCapabilityFixed + * Returns true if width, height and framerate was specified when the Start() was called. + */ +bool ViECapturer::CaptureCapabilityFixed() +{ + return _requestedCapability.width != 0 && _requestedCapability.height != 0 + && _requestedCapability.maxFPS != 0; +} + +// ---------------------------------------------------------------------------- +// Implements VideoEncoder +// +// ---------------------------------------------------------------------------- +WebRtc_Word32 ViECapturer::Version(WebRtc_Word8 *version, WebRtc_Word32 length) const +{ + return 0; +} + +WebRtc_Word32 ViECapturer::InitEncode(const VideoCodec* codecSettings, + WebRtc_Word32 numberOfCores, + WebRtc_UWord32 maxPayloadSize) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d)", __FUNCTION__, _captureId); + + CriticalSectionScoped cs(_encodingCritsect); + if (!_captureEncoder || !codecSettings) + return WEBRTC_VIDEO_CODEC_ERROR; + + if (_vcm) // Initialize VCM to be able to decode frames if needed. + { + if (_vcm->InitializeReceiver() == 0) + { + if (_vcm->RegisterReceiveCallback(this) == 0) + { + if (_vcm->RegisterReceiveCodec(codecSettings, numberOfCores, + false) == 0) + { + _decoderInitialized = true; + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d) VCM Decoder initialized", + __FUNCTION__, _captureId); + } + } + } + } + return _captureEncoder->ConfigureEncoder(*codecSettings, maxPayloadSize); +} + +/* + * Encode + * Orders the Capture device to create a certain frame type. + */ +WebRtc_Word32 ViECapturer::Encode(const RawImage& inputImage, + const void* codecSpecificInfo, /*= NULL,*/ + VideoFrameType frameType /*= kDeltaFrame*/) +{ + + CriticalSectionScoped cs(_encodingCritsect); + + if (!_captureEncoder) + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + + if (frameType == kKeyFrame) + return _captureEncoder->EncodeFrameType(kVideoFrameKey); + + if (frameType == kSkipFrame) + return _captureEncoder->EncodeFrameType(kFrameEmpty); + + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + +} + +WebRtc_Word32 ViECapturer::RegisterEncodeCompleteCallback( EncodedImageCallback* callback) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d)", __FUNCTION__, _captureId); + + CriticalSectionScoped cs(_deliverCritsect); + if (!_captureEncoder) + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + + _encodeCompleteCallback = callback; + return 0; + +} +WebRtc_Word32 ViECapturer::Release() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d)", __FUNCTION__, _captureId); + + { + CriticalSectionScoped cs(_deliverCritsect); + _encodeCompleteCallback = NULL; + } + + { + CriticalSectionScoped cs(_encodingCritsect); + + _decoderInitialized = false; + _codec.codecType = kVideoCodecUnknown; + _captureEncoder->ConfigureEncoder(_codec, 0); // Reset the camera to output I420. + + if (_vieEncoder) // Need to add the encoder as an observer of I420. + { + ViEFrameProviderBase::RegisterFrameCallback(_vieEncoderId, + _vieEncoder); + } + _vieEncoder = NULL; + } + return 0; +} + +/* + * Reset + * Should reset the capture device to the state it was in after the InitEncode function. + * Current implementation do nothing. + */ +WebRtc_Word32 ViECapturer::Reset() +{ + + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d)", __FUNCTION__, _captureId); + return 0; + +} +WebRtc_Word32 ViECapturer::SetPacketLoss(WebRtc_UWord32 packetLoss) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d)", __FUNCTION__, _captureId); + + CriticalSectionScoped cs(_encodingCritsect); + if (!_captureEncoder) + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + + return _captureEncoder->SetPacketLoss(packetLoss); +} + +WebRtc_Word32 ViECapturer::SetRates(WebRtc_UWord32 newBitRate, + WebRtc_UWord32 frameRate) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s(captureDeviceId: %d)", __FUNCTION__, _captureId); + + CriticalSectionScoped cs(_encodingCritsect); + if (!_captureEncoder) + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + + return _captureEncoder->SetRates(newBitRate, frameRate); +} + +/* + * FrameToRender - implements VCMReceiveCallback. + * (VCM decode callback) Used in order to be able to provide I420 frames to renderer etc. + */ + +WebRtc_Word32 ViECapturer::FrameToRender(VideoFrame& videoFrame) +{ + _deliverCritsect.Enter(); + DeliverI420Frame(videoFrame); + _deliverCritsect.Leave(); + return 0; +} + +/******************************************************************************/ + +// +// Statistics Observer functions +// +WebRtc_Word32 ViECapturer::RegisterObserver(ViECaptureObserver& observer) +{ + if (_observer) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _captureId), + "%s Observer already registered", __FUNCTION__, + _captureId); + return -1; + } + if (_captureModule->RegisterCaptureCallback(*this) != 0) + { + return -1; + } + _captureModule->EnableFrameRateCallback(true); + _captureModule->EnableNoPictureAlarm(true); + _observer = &observer; + return 0; +} + +WebRtc_Word32 ViECapturer::DeRegisterObserver() +{ + CriticalSectionScoped cs(_observerCritsect); + if (!_observer) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _captureId), + "%s No observer registered", __FUNCTION__, _captureId); + return -1; + } + _captureModule->EnableFrameRateCallback(false); + _captureModule->EnableNoPictureAlarm(false); + _captureModule->DeRegisterCaptureCallback(); + _observer = NULL; + return 0; + +} +bool ViECapturer::IsObserverRegistered() +{ + CriticalSectionScoped cs(_observerCritsect); + return _observer != NULL; +} +// ---------------------------------------------------------------------------- +// Implements VideoCaptureFeedBack +// +// ---------------------------------------------------------------------------- +void ViECapturer::OnCaptureFrameRate(const WebRtc_Word32 id, + const WebRtc_UWord32 frameRate) +{ + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, + ViEId(_engineId, _captureId), "OnCaptureFrameRate %d", + frameRate); + + CriticalSectionScoped cs(_observerCritsect); + _observer->CapturedFrameRate(_id, (WebRtc_UWord8) frameRate); +} + +void ViECapturer::OnNoPictureAlarm(const WebRtc_Word32 id, + const VideoCaptureAlarm alarm) +{ + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, + ViEId(_engineId, _captureId), "OnNoPictureAlarm %d", alarm); + + CriticalSectionScoped cs(_observerCritsect); + CaptureAlarm vieAlarm = (alarm == Raised) ? AlarmRaised : AlarmCleared; + _observer->NoPictureAlarm(id, vieAlarm); +} +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViECapturer::SetCaptureDeviceImage(const VideoFrame& captureDeviceImage) +{ + return _captureModule->StartSendImage(captureDeviceImage, 10); +} + +} // namespace webrtc diff --git a/video_engine/main/source/vie_capturer.h b/video_engine/main/source/vie_capturer.h new file mode 100644 index 0000000000..9e67f505a3 --- /dev/null +++ b/video_engine/main/source/vie_capturer.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_capturer.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CAPTURER_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CAPTURER_H_ + +// Defines +#include "engine_configurations.h" +#include "vie_defines.h" +#include "typedefs.h" + +#include "video_capture.h" +#include "video_processing.h" +#include "vie_frame_provider_base.h" +#include "video_codec_interface.h" +#include "video_coding.h" +#include "vie_capture.h" +#include "common_types.h" + +// Forward declarations +struct ViEPicture; + +namespace webrtc { +class CriticalSectionWrapper; +class EventWrapper; +class ThreadWrapper; +class ViEEffectFilter; +class ViEEncoder; +class ProcessThread; + +class ViECapturer: public ViEFrameProviderBase, + public ViEExternalCapture, // External capture + protected VideoCaptureDataCallback, + protected VideoEncoder, + protected VCMReceiveCallback, + protected VideoCaptureFeedBack +{ +public: + static ViECapturer* CreateViECapture(int captureId, int, + VideoCaptureModule& captureModule, + ProcessThread& moduleProcessThread); + + static ViECapturer* CreateViECapture(int captureId, int engineId, + const WebRtc_UWord8* deviceUniqueIdUTF8, + WebRtc_UWord32 deviceUniqueIdUTF8Length, + ProcessThread& moduleProcessThread); + ~ViECapturer(); + + //Override ViEFrameProviderBase + int FrameCallbackChanged(); + virtual int DeregisterFrameCallback(const ViEFrameCallback* callbackObject); + bool IsFrameCallbackRegistered(const ViEFrameCallback* callbackObject); + + // Implements ExternalCapture + virtual int IncomingFrame(unsigned char* videoFrame, + unsigned int videoFrameLength, + unsigned short width, unsigned short height, + RawVideoType videoType, + unsigned long long captureTime = 0); + + // Use this capture device as encoder. Returns 0 if the codec is supported by this capture device. + virtual WebRtc_Word32 PreEncodeToViEEncoder(const VideoCodec& codec, + ViEEncoder& vieEncoder, + WebRtc_Word32 vieEncoderId); + + // Start/Stop + WebRtc_Word32 Start(const CaptureCapability captureCapability = + CaptureCapability()); + WebRtc_Word32 Stop(); + bool Started(); + + WebRtc_Word32 SetCaptureDelay(WebRtc_Word32 delayMS); + WebRtc_Word32 SetRotateCapturedFrames(const RotateCapturedFrame rotation); + + // Effect filter + WebRtc_Word32 RegisterEffectFilter(ViEEffectFilter* effectFilter); + WebRtc_Word32 EnableDenoising(bool enable); + WebRtc_Word32 EnableDeflickering(bool enable); + WebRtc_Word32 EnableBrightnessAlarm(bool enable); + + // Statistic observer + WebRtc_Word32 RegisterObserver(ViECaptureObserver& observer); + WebRtc_Word32 DeRegisterObserver(); + bool IsObserverRegistered(); + + //Information + const WebRtc_UWord8* CurrentDeviceName() const; + + // set device images + WebRtc_Word32 SetCaptureDeviceImage(const VideoFrame& captureDeviceImage); + +protected: + ViECapturer(int captureId, int engineId, + ProcessThread& moduleProcessThread); + + WebRtc_Word32 Init(VideoCaptureModule& captureModule); + WebRtc_Word32 Init(const WebRtc_UWord8* deviceUniqueIdUTF8, + const WebRtc_UWord32 deviceUniqueIdUTF8Length); + + // Implements VideoCaptureDataCallback + virtual void OnIncomingCapturedFrame(const WebRtc_Word32 id, + VideoFrame& videoFrame, + VideoCodecType codecType); + virtual void OnCaptureDelayChanged(const WebRtc_Word32 id, + const WebRtc_Word32 delay); + bool EncoderActive(); + bool CaptureCapabilityFixed(); // Returns true if the capture capability has been set in the StartCapture function and may not be changed. + WebRtc_Word32 IncImageProcRefCount(); + WebRtc_Word32 DecImageProcRefCount(); + + // Implements VideoEncoder + virtual WebRtc_Word32 Version(WebRtc_Word8 *version, WebRtc_Word32 length) const; + virtual WebRtc_Word32 InitEncode(const VideoCodec* codecSettings, + WebRtc_Word32 numberOfCores, + WebRtc_UWord32 maxPayloadSize); + virtual WebRtc_Word32 Encode(const RawImage& inputImage, + const void* codecSpecificInfo = NULL, + VideoFrameType frameType = kDeltaFrame); + virtual WebRtc_Word32 RegisterEncodeCompleteCallback( + EncodedImageCallback* callback); + virtual WebRtc_Word32 Release(); + virtual WebRtc_Word32 Reset(); + virtual WebRtc_Word32 SetPacketLoss(WebRtc_UWord32 packetLoss); + virtual WebRtc_Word32 SetRates(WebRtc_UWord32 newBitRate, + WebRtc_UWord32 frameRate); + + // Implements VCMReceiveCallback + virtual WebRtc_Word32 FrameToRender(VideoFrame& videoFrame); + // Implements VideoCaptureFeedBack + virtual void OnCaptureFrameRate(const WebRtc_Word32 id, + const WebRtc_UWord32 frameRate); + virtual void OnNoPictureAlarm(const WebRtc_Word32 id, + const VideoCaptureAlarm alarm); + + // Thread functions for deliver captured frames to receivers + static bool ViECaptureThreadFunction(void* obj); + bool ViECaptureProcess(); + + void DeliverI420Frame(VideoFrame& videoFrame); + void DeliverCodedFrame(VideoFrame& videoFrame); + +private: + enum {kThreadWaitTimeMs = 100}; + + CriticalSectionWrapper& _captureCritsect; // Never take this one before deliverCritsect! + CriticalSectionWrapper& _deliverCritsect; + VideoCaptureModule* _captureModule; + bool _useExternalModule; + VideoCaptureExternal* _externalCaptureModule; + ProcessThread& _moduleProcessThread; + const int _captureId; + + // Capture thread + ThreadWrapper& _vieCaptureThread; + EventWrapper& _vieCaptureEvent; + EventWrapper& _vieDeliverEvent; + + VideoFrame _capturedFrame; + VideoFrame _deliverFrame; + VideoFrame _encodedFrame; + + // Image processing + ViEEffectFilter* _effectFilter; + VideoProcessingModule* _imageProcModule; + int _imageProcModuleRefCounter; + VideoProcessingModule::FrameStats* _deflickerFrameStats; + VideoProcessingModule::FrameStats* _brightnessFrameStats; + Brightness _currentBrightnessLevel; + Brightness _reportedBrightnessLevel; + bool _denoisingEnabled; + + //Statistic observer + CriticalSectionWrapper& _observerCritsect; + ViECaptureObserver* _observer; + + // Encoding using encoding capable cameras + CriticalSectionWrapper& _encodingCritsect; + VideoCaptureModule::VideoCaptureEncodeInterface* _captureEncoder; + EncodedImageCallback* _encodeCompleteCallback; + VideoCodec _codec; + ViEEncoder* _vieEncoder; //ViEEncoder we are encoding for. + WebRtc_Word32 _vieEncoderId; //ViEEncoder id we are encoding for. + VideoCodingModule* _vcm; // Used for decoding preencoded frames + EncodedVideoData _decodeBuffer; // Used for decoding preencoded frames + bool _decoderInitialized; + CaptureCapability _requestedCapability; + + VideoFrame _captureDeviceImage; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CAPTURER_H_ diff --git a/video_engine/main/source/vie_channel.cc b/video_engine/main/source/vie_channel.cc new file mode 100644 index 0000000000..aeaf9ffe6b --- /dev/null +++ b/video_engine/main/source/vie_channel.cc @@ -0,0 +1,3222 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * ViEChannel.cpp + */ + +#include "vie_channel.h" +#include "vie_defines.h" + +#include "critical_section_wrapper.h" +#include "rtp_rtcp.h" +#include "udp_transport.h" +#include "video_coding.h" +#include "video_processing.h" +#include "video_render_defines.h" +#ifdef WEBRTC_SRTP +#include "SrtpModule.h" +#endif +#include "process_thread.h" +#include "trace.h" +#include "thread_wrapper.h" +#include "vie_codec.h" +#include "vie_errors.h" +#include "vie_image_process.h" +#include "vie_rtp_rtcp.h" +#include "vie_receiver.h" +#include "vie_sender.h" +#include "vie_sync_module.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViEChannel::ViEChannel(WebRtc_Word32 channelId, WebRtc_Word32 engineId, + WebRtc_UWord32 numberOfCores, + ProcessThread& moduleProcessThread) : + ViEFrameProviderBase(channelId, engineId), + _channelId(channelId), + _engineId(engineId), + _numberOfCores(numberOfCores), + _numSocketThreads(kViESocketThreads), + _callbackCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _dataCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _rtpRtcp(*RtpRtcp::CreateRtpRtcp( + ViEModuleId(engineId, channelId), false)), +#ifndef WEBRTC_EXTERNAL_TRANSPORT + _socketTransport( + *UdpTransport::Create( + ViEModuleId(engineId, channelId), _numSocketThreads)), +#endif + _vcm(*VideoCodingModule::Create( + ViEModuleId(engineId, channelId))), + _vieReceiver(*(new ViEReceiver(engineId, channelId, _rtpRtcp, _vcm))), + _vieSender(*(new ViESender(engineId, channelId, _rtpRtcp))), + _vieSync(*(new ViESyncModule(ViEId(engineId, channelId), _vcm, + _rtpRtcp))), + _moduleProcessThread(moduleProcessThread), + _codecObserver(NULL), + _doKeyFrameCallbackRequest(false), + _rtpObserver(NULL), + _rtcpObserver(NULL), + _networkObserver(NULL), + _rtpPacketTimeout(false), + _usingPacketSpread(false), + _ptrExternalTransport(NULL), + _decoderReset(true), + _waitForKeyFrame(false), + _ptrDecodeThread(false), + _ptrSrtpModuleEncryption(NULL), + _ptrSrtpModuleDecryption(NULL), + _ptrExternalEncryption(NULL), + _effectFilter(NULL), + _colorEnhancement(true), + _vcmRTTReported(TickTime::Now()), + _fileRecorder(channelId) +{ + WEBRTC_TRACE( + webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(engineId, channelId), + "ViEChannel::ViEChannel(channelId: %d, engineId: %d) - Constructor", + channelId, engineId); +} + +WebRtc_Word32 ViEChannel::Init() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: channelId: %d, engineId: %d)", __FUNCTION__, _channelId, + _engineId); + // RTP/RTCP initialization + if (_rtpRtcp.InitSender() != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: RTP::InitSender failure", + __FUNCTION__); + return -1; + } + if (_rtpRtcp.SetSendingMediaStatus(false) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: RTP::SetSendingMediaStatus failure", __FUNCTION__); + return -1; + } + if (_rtpRtcp.InitReceiver() != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: RTP::InitReceiver failure", __FUNCTION__); + return -1; + } + if (_rtpRtcp.RegisterIncomingDataCallback((RtpData*) &_vieReceiver) + != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: RTP::RegisterIncomingDataCallback failure", + __FUNCTION__); + return -1; + } + if (_rtpRtcp.RegisterSendTransport((Transport*) &_vieSender) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: RTP::RegisterSendTransport failure", __FUNCTION__); + return -1; + } + if (_moduleProcessThread.RegisterModule(&_rtpRtcp) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: RTP::RegisterModule failure", __FUNCTION__); + return -1; + } + if (_rtpRtcp.SetKeyFrameRequestMethod(kKeyFrameReqFirRtp) != 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId,_channelId), + "%s: RTP::SetKeyFrameRequestMethod failure", __FUNCTION__); + } + if (_rtpRtcp.SetRTCPStatus(kRtcpCompound) != 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: RTP::SetRTCPStatus failure", __FUNCTION__); + } + if (_rtpRtcp.RegisterIncomingRTPCallback(this) != 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: RTP::RegisterIncomingRTPCallback failure", + __FUNCTION__); + return -1; + } + + if (_rtpRtcp.RegisterIncomingRTCPCallback(this) != 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: RTP::RegisterIncomingRTCPCallback failure", + __FUNCTION__); + return -1; + } + + // VCM initialization + if (_vcm.InitializeReceiver() != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: VCM::InitializeReceiver failure", __FUNCTION__); + return -1; + } + if (_vcm.RegisterReceiveCallback(this) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: VCM::RegisterReceiveCallback failure", __FUNCTION__); + return -1; + } + if (_vcm.RegisterFrameTypeCallback(this) != 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: VCM::RegisterFrameTypeCallback failure", __FUNCTION__); + } + if (_vcm.RegisterReceiveStatisticsCallback(this) != 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: VCM::RegisterReceiveStatisticsCallback failure", + __FUNCTION__); + } + if (_vcm.SetRenderDelay(kViEDefaultRenderDelayMs) != 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: VCM::SetRenderDelay failure", __FUNCTION__); + } + if (_moduleProcessThread.RegisterModule(&_vcm) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: VCM::RegisterModule(vcm) failure", __FUNCTION__); + return -1; + } +#ifdef VIDEOCODEC_VP8 + VideoCodec videoCodec; + if (_vcm.Codec(kVideoCodecVP8, &videoCodec) == VCM_OK) + { + _rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType); + _rtpRtcp.RegisterReceivePayload(videoCodec.plName, videoCodec.plType); + _vcm.RegisterReceiveCodec(&videoCodec, _numberOfCores); + _vcm.RegisterSendCodec(&videoCodec, _numberOfCores, + _rtpRtcp.MaxDataPayloadLength()); + } + else + { + assert(false); + } +#endif + + return 0; +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViEChannel::~ViEChannel() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "ViEChannel Destructor, channelId: %d, engineId: %d", + _channelId, _engineId); + + // Make sure we don't get more callbacks from the RTP module. + _rtpRtcp.RegisterIncomingRTPCallback(NULL); + _rtpRtcp.RegisterSendTransport(NULL); +#ifndef WEBRTC_EXTERNAL_TRANSPORT + _socketTransport.StopReceiving(); +#endif + _moduleProcessThread.DeRegisterModule(&_rtpRtcp); + _moduleProcessThread.DeRegisterModule(&_vcm); + _moduleProcessThread.DeRegisterModule(&_vieSync); + + if (_ptrDecodeThread) + { + StopDecodeThread(); + } + + delete &_vieReceiver; + delete &_vieSender; + delete &_vieSync; + + delete &_callbackCritsect; + delete &_dataCritsect; + + // Release modules + + RtpRtcp::DestroyRtpRtcp(&_rtpRtcp); +#ifndef WEBRTC_EXTERNAL_TRANSPORT + UdpTransport::Destroy( + &_socketTransport); +#endif + VideoCodingModule::Destroy(&_vcm); +} + +// ============================================================================ +// Codec +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetSendCodec +// +// videoCodec: encoder settings +// newStream: the encoder type has changed and we should start a new RTP stream +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetSendCodec(const VideoCodec& videoCodec, + bool newStream) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: codecType: %d", __FUNCTION__, videoCodec.codecType); + + if (videoCodec.codecType == kVideoCodecRED || + videoCodec.codecType == kVideoCodecULPFEC) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: codecType: %d is not a valid send codec.", + __FUNCTION__, videoCodec.codecType); + return -1; + } + + // Update the RTP module with the settigns + // Stop and Start the RTP module -> trigger new SSRC + bool restartRtp = false; + if (_rtpRtcp.Sending() && newStream) + { + restartRtp = true; + _rtpRtcp.SetSendingStatus(false); + } + + if (_rtpRtcp.SetSendBitrate(videoCodec.startBitrate * 1000, + videoCodec.minBitrate, videoCodec.maxBitrate) + != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: could not set send bitrates", __FUNCTION__); + return -1; + } + /* TODO Enable this if H264 is available. + * This sets the wanted packetization mode. + if(videoCodec.plType==kVideoCodecH264) + { + if (videoCodec.codecSpecific.H264.packetization == kH264SingleMode) + { + _rtpRtcp.SetH264PacketizationMode (H264_SINGLE_NAL_MODE); + } + else + { + _rtpRtcp.SetH264PacketizationMode(H264_NON_INTERLEAVED_MODE); + } + if (videoCodec.codecSpecific.H264.configParametersSize > 0) + { + _rtpRtcp.SetH264SendModeNALU_PPS_SPS(true); + } + }*/ + + // Don't log this error, no way to chek in advance if this plType is + // registered or not... + _rtpRtcp.DeRegisterSendPayload(videoCodec.plType); + if (_rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: could not register payload type", __FUNCTION__); + return -1; + } + + if (restartRtp) + { + _rtpRtcp.SetSendingStatus(true); + } + return 0; +} + +// ---------------------------------------------------------------------------- +// SetReceiveCodec +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetReceiveCodec(const VideoCodec& videoCodec) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + _rtpRtcp.DeRegisterReceivePayload(videoCodec.plType); + if (_rtpRtcp.RegisterReceivePayload(videoCodec.plName, videoCodec.plType) + != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not register receive payload type", __FUNCTION__); + return -1; + } + + if (videoCodec.codecType != kVideoCodecRED && + videoCodec.codecType != kVideoCodecULPFEC) + { //Register codec type with VCM. But do not register RED or ULPFEC + if (_vcm.RegisterReceiveCodec(&videoCodec, _numberOfCores, + _waitForKeyFrame) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not register decoder", __FUNCTION__); + return -1; + } + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetReceiveCodec +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetReceiveCodec(VideoCodec& videoCodec) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_vcm.ReceiveCodec(&videoCodec) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not get receive codec", __FUNCTION__); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterCodecObserver +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::RegisterCodecObserver(ViEDecoderObserver* observer) +{ + CriticalSectionScoped cs(_callbackCritsect); + if (observer) + { + if (_codecObserver) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: alread added", + __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: observer added", __FUNCTION__); + _codecObserver = observer; + } + else + { + if (!_codecObserver) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: no observer added", + __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: observer removed", __FUNCTION__); + _codecObserver = NULL; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterExternalDecoder +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::RegisterExternalDecoder( + const WebRtc_UWord8 plType, VideoDecoder* decoder, + bool decoderRender, //Decoder also render + WebRtc_Word32 renderDelay) // Decode and render delay +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + WebRtc_Word32 result = 0; + result = _vcm.RegisterExternalDecoder(decoder, plType, decoderRender); + if (decoderRender && result == 0) + { + // Let VCM know how long before the actual render time the decoder needs + // to get a frame for decoding. + result = _vcm.SetRenderDelay(renderDelay); + } + return result; +} + +// ---------------------------------------------------------------------------- +// DeRegisterExternalDecoder +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::DeRegisterExternalDecoder(const WebRtc_UWord8 plType) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s plType", __FUNCTION__, plType); + + VideoCodec currentReceiveCodec; + WebRtc_Word32 result = 0; + result = _vcm.ReceiveCodec(¤tReceiveCodec); + if (_vcm.RegisterExternalDecoder(NULL, plType, false) != VCM_OK) + { + return -1; + } + + if (result == 0 && currentReceiveCodec.plType == plType) + { + result = _vcm.RegisterReceiveCodec(¤tReceiveCodec, + _numberOfCores, _waitForKeyFrame); + } + + return result; +} + +// ---------------------------------------------------------------------------- +// ReceiveCodecStatistics +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::ReceiveCodecStatistics(WebRtc_UWord32& numKeyFrames, + WebRtc_UWord32& numDeltaFrames) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + VCMFrameCount receivedFrames; + if (_vcm.ReceivedFrameCount(receivedFrames) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not get received frame information", __FUNCTION__); + return -1; + } + numKeyFrames = receivedFrames.numKeyFrames; + numDeltaFrames = receivedFrames.numDeltaFrames; + return 0; +} + +// ---------------------------------------------------------------------------- +// WaitForKeyFrame +// +// Only affects calls to SetReceiveCodec done after this call. +// Default = false +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::WaitForKeyFrame(bool wait) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(wait: %d)", __FUNCTION__, wait); + + _waitForKeyFrame = wait; + return 0; +} + +// ---------------------------------------------------------------------------- +// SetSignalPacketLossStatus +// +// If enabled, a key frame request will be sent as soon as there are lost +// packets. If onlyKeyFrames are set, requests are only sent for loss in key +// frames. +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetSignalPacketLossStatus(bool enable, + bool onlyKeyFrames) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(enable: %d)", __FUNCTION__, enable); + + if (enable) + { + if (onlyKeyFrames) + { + _vcm.SetVideoProtection(kProtectionKeyOnLoss, false); + if (_vcm.SetVideoProtection(kProtectionKeyOnKeyLoss, true) + != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s failed %d", __FUNCTION__, enable); + return -1; + } + } + else + { + _vcm.SetVideoProtection(kProtectionKeyOnKeyLoss, false); + if (_vcm.SetVideoProtection(kProtectionKeyOnLoss, true) + != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s failed %d", __FUNCTION__, enable); + return -1; + } + } + } + else + { + _vcm.SetVideoProtection(kProtectionKeyOnLoss, false); + _vcm.SetVideoProtection(kProtectionKeyOnKeyLoss, false); + } + return 0; +} + +// ============================================================================ +// RTP/RTCP +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetRTCPMode +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetRTCPMode(const RTCPMethod rtcpMode) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: %d", __FUNCTION__, rtcpMode); + + return _rtpRtcp.SetRTCPStatus(rtcpMode); +} + +// ---------------------------------------------------------------------------- +// GetRTCPMode +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetRTCPMode(RTCPMethod& rtcpMode) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + rtcpMode = _rtpRtcp.RTCP(); + return 0; +} + +// ---------------------------------------------------------------------------- +// EnableNACKStatus +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetNACKStatus(const bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(enable: %d)", __FUNCTION__, enable); + + // Update the decoding VCM + if (_vcm.SetVideoProtection(kProtectionNack, enable) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not set VCM NACK protection: %d", __FUNCTION__, + enable); + return -1; + } + if (enable) + { + // Disable possible FEC + SetFECStatus(false, 0, 0); + + // Turn on NACK, + NACKMethod nackMethod = kNackRtcp; + if (_rtpRtcp.RTCP() == kRtcpOff) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not enable NACK, RTPC not on ", __FUNCTION__); + return -1; + } + if (_rtpRtcp.SetNACKStatus(nackMethod) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not set NACK method %d", __FUNCTION__, + nackMethod); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: Using NACK method %d", __FUNCTION__, nackMethod); + _rtpRtcp.SetStorePacketsStatus(true, kNackHistorySize); + _vcm.RegisterPacketRequestCallback(this); + } + else + { + _rtpRtcp.SetStorePacketsStatus(false); + _vcm.RegisterPacketRequestCallback(NULL); + if (_rtpRtcp.SetNACKStatus(kNackOff) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not turn off NACK", __FUNCTION__); + return -1; + } + } + return 0; +} + +// ---------------------------------------------------------------------------- +// SetFECStatus +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetFECStatus(const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(enable: %d, payloadTypeRED: %u, payloadTypeFEC: %u)", + __FUNCTION__, enable, payloadTypeRED, payloadTypeFEC); + + // Disable possible NACK + if (enable) + { + SetNACKStatus(false); + } + + if (_rtpRtcp.SetGenericFECStatus(enable, payloadTypeRED, payloadTypeFEC) + != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not change FEC status to %d", __FUNCTION__, + enable); + return -1; + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// KeyFrameRequestMethod +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetKeyFrameRequestMethod( + const KeyFrameRequestMethod method) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: %d", __FUNCTION__, method); + + return _rtpRtcp.SetKeyFrameRequestMethod(method); +} + +// ---------------------------------------------------------------------------- +// EnableTMMBR +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::EnableTMMBR(const bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: %d", __FUNCTION__, enable); + + return _rtpRtcp.SetTMMBRStatus(enable); +} + +// ---------------------------------------------------------------------------- +// EnableKeyFrameRequestCallback +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::EnableKeyFrameRequestCallback(const bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: %d", __FUNCTION__, enable); + + CriticalSectionScoped cs(_callbackCritsect); + if (enable && _codecObserver == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: No ViECodecObserver set", __FUNCTION__, enable); + return -1; + } + _doKeyFrameCallbackRequest = enable; + return 0; + +} + +// ---------------------------------------------------------------------------- +// SetSSRC +// +// Sets SSRC for outgoing stream +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetSSRC(const WebRtc_UWord32 SSRC) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(SSRC: %u)", __FUNCTION__, SSRC); + + return _rtpRtcp.SetSSRC(SSRC); +} + +// ---------------------------------------------------------------------------- +// SetSSRC +// +// Gets SSRC for outgoing stream +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetLocalSSRC(WebRtc_UWord32& SSRC) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + SSRC = _rtpRtcp.SSRC(); + return 0; +} + +// ---------------------------------------------------------------------------- +// GetRemoteSSRC +// +// Gets SSRC for the incoming stream +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetRemoteSSRC(WebRtc_UWord32& SSRC) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + SSRC = _rtpRtcp.RemoteSSRC(); + return 0; +} + +// ---------------------------------------------------------------------------- +// GetRemoteCSRC +// +// Gets the CSRC for the incoming stream +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetRemoteCSRC(unsigned int CSRCs[kRtpCsrcSize]) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + WebRtc_UWord32 arrayCSRC[kRtpCsrcSize]; + memset(arrayCSRC, 0, sizeof(arrayCSRC)); + + WebRtc_Word32 numCSRCs = _rtpRtcp.RemoteCSRCs(arrayCSRC); + if (numCSRCs > 0) + { + memcpy(CSRCs, arrayCSRC, numCSRCs * sizeof(WebRtc_UWord32)); + for (int idx = 0; idx < numCSRCs; idx++) + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "\tCSRC[%d] = %lu", idx, + CSRCs[idx]); + } + } + else + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: CSRC list is empty", __FUNCTION__); + } + return 0; +} + +// ---------------------------------------------------------------------------- +// SetStartSequenceNumber +// +// Sets the starting sequence number, must be called before StartSend. +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetStartSequenceNumber(WebRtc_UWord16 sequenceNumber) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_rtpRtcp.Sending()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: already sending", + __FUNCTION__); + return -1; + } + return _rtpRtcp.SetSequenceNumber(sequenceNumber); +} + +// ---------------------------------------------------------------------------- +// SetRTCPCName +// +// Sets the CName for the outgoing stream on the channel +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetRTCPCName(const WebRtc_Word8 rtcpCName[]) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_rtpRtcp.Sending()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: already sending", + __FUNCTION__); + return -1; + } + return _rtpRtcp.SetCNAME(rtcpCName); +} + +// ---------------------------------------------------------------------------- +// GetRTCPCName +// +// Gets the CName for the outgoing stream on the channel +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetRTCPCName(WebRtc_Word8 rtcpCName[]) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + return _rtpRtcp.CNAME(rtcpCName); +} + +// ---------------------------------------------------------------------------- +// GetRemoteRTCPCName +// +// Gets the CName of the incoming stream +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetRemoteRTCPCName(WebRtc_Word8 rtcpCName[]) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + WebRtc_UWord32 remoteSSRC = _rtpRtcp.RemoteSSRC(); + return _rtpRtcp.RemoteCNAME(remoteSSRC, rtcpCName); +} + +// ---------------------------------------------------------------------------- +// RegisterRtpObserver +// +// Registers an RTP observer +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::RegisterRtpObserver(ViERTPObserver* observer) +{ + CriticalSectionScoped cs(_callbackCritsect); + if (observer) + { + if (_rtpObserver) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: observer alread added", __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: observer added", __FUNCTION__); + _rtpObserver = observer; + } + else + { + if (!_rtpObserver) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: no observer added", + __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: observer removed", __FUNCTION__); + _rtpObserver = NULL; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterRtcpObserver +// +// Registers an RTPC observer +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::RegisterRtcpObserver(ViERTCPObserver* observer) +{ + CriticalSectionScoped cs(_callbackCritsect); + if (observer) + { + if (_rtcpObserver) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: observer alread added", __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: observer added", __FUNCTION__); + _rtcpObserver = observer; + } + else + { + if (!_rtcpObserver) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: no observer added", + __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: observer removed", __FUNCTION__); + _rtcpObserver = NULL; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// SendApplicationDefinedRTCPPacket +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SendApplicationDefinedRTCPPacket( + const WebRtc_UWord8 subType, WebRtc_UWord32 name, const WebRtc_UWord8* data, + WebRtc_UWord16 dataLengthInBytes) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + // Sanity checks + if (!_rtpRtcp.Sending()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: not sending", + __FUNCTION__); + return -1; + } + if (data == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: no input argument", + __FUNCTION__); + return -1; + } + if (dataLengthInBytes % 4 != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: input length error", + __FUNCTION__); + return -1; + } + RTCPMethod rtcpMethod = _rtpRtcp.RTCP(); + if (rtcpMethod == kRtcpOff) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: RTCP not enabled", + __FUNCTION__); + return -1; + } + // Create and send packet + if (_rtpRtcp.SetRTCPApplicationSpecificData(subType, name, data, + dataLengthInBytes) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not send RTCP application data", __FUNCTION__); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetSendRtcpStatistics +// +// Gets statistics sent in RTCP packets to remote side +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetSendRtcpStatistics(WebRtc_UWord16& fractionLost, + WebRtc_UWord32& cumulativeLost, + WebRtc_UWord32& extendedMax, + WebRtc_UWord32& jitterSamples, + WebRtc_Word32& rttMs) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + WebRtc_UWord32 remoteSSRC = _rtpRtcp.RemoteSSRC(); + + RTCPReportBlock remoteStat; + if (_rtpRtcp.RemoteRTCPStat(remoteSSRC, &remoteStat) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not get remote stats", __FUNCTION__); + return -1; + } + fractionLost = remoteStat.fractionLost; + cumulativeLost = remoteStat.cumulativeLost; + extendedMax = remoteStat.extendedHighSeqNum; + jitterSamples = remoteStat.jitter; + + WebRtc_UWord16 dummy; + WebRtc_UWord16 rtt = 0; + if (_rtpRtcp.RTT(remoteSSRC, &rtt, &dummy, &dummy, &dummy) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Could not get RTT", + __FUNCTION__); + return -1; + } + rttMs = rtt; + return 0; +} + +// ---------------------------------------------------------------------------- +// GetSendRtcpStatistics +// +// Gets statistics received in RTCP packets from remote side +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetReceivedRtcpStatistics( + WebRtc_UWord16& fractionLost, WebRtc_UWord32& cumulativeLost, + WebRtc_UWord32& extendedMax, WebRtc_UWord32& jitterSamples, + WebRtc_Word32& rttMs) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + WebRtc_UWord8 fracLost = 0; + if (_rtpRtcp.StatisticsRTP(&fracLost, &cumulativeLost, &extendedMax, + &jitterSamples) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not get received RTP statistics", __FUNCTION__); + return -1; + } + fractionLost = fracLost; + + WebRtc_UWord32 remoteSSRC = _rtpRtcp.RemoteSSRC(); + WebRtc_UWord16 dummy = 0; + WebRtc_UWord16 rtt = 0; + if (_rtpRtcp.RTT(remoteSSRC, &rtt, &dummy, &dummy, &dummy) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Could not get RTT", + __FUNCTION__); + return -1; + } + rttMs = rtt; + return 0; +} + +// ---------------------------------------------------------------------------- +// GetRtpStatistics +// +// Gets sent/received packets statistics +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetRtpStatistics( + WebRtc_UWord32& bytesSent, WebRtc_UWord32& packetsSent, + WebRtc_UWord32& bytesReceived, WebRtc_UWord32& packetsReceived) const +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_rtpRtcp.DataCountersRTP(&bytesSent, &packetsSent, &bytesReceived, + &packetsReceived) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Could not get RTT", + __FUNCTION__); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// SetKeepAliveStatus +// +// Enables/disbles RTP keeoalive +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetKeepAliveStatus( + const bool enable, const WebRtc_Word8 unknownPayloadType, + const WebRtc_UWord16 deltaTransmitTimeMS) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (enable && _rtpRtcp.RTPKeepalive()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: RTP keepalive already enabled", __FUNCTION__); + return -1; + } + else if (!enable && !_rtpRtcp.RTPKeepalive()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: RTP keepalive already disabled", __FUNCTION__); + return -1; + } + + if (_rtpRtcp.SetRTPKeepaliveStatus(enable, unknownPayloadType, + deltaTransmitTimeMS) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not set RTP keepalive status %d", __FUNCTION__, + enable); + if (enable == false && !_rtpRtcp.DefaultModuleRegistered()) + { + // Not sending media and we try to disable keep alive + _rtpRtcp.ResetSendDataCountersRTP(); + _rtpRtcp.SetSendingStatus(false); + } + return -1; + } + + if (enable && !_rtpRtcp.Sending()) + { + // Enable sending to start sending Sender reports instead of receive + // reports + if (_rtpRtcp.SetSendingStatus(true) != 0) + { + _rtpRtcp.SetRTPKeepaliveStatus(false, 0, 0); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not start sending", __FUNCTION__); + return -1; + } + } + else if (!enable && !_rtpRtcp.SendingMedia()) + { + // Not sending media and we're disabling keep alive + _rtpRtcp.ResetSendDataCountersRTP(); + if (_rtpRtcp.SetSendingStatus(false) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not stop sending", __FUNCTION__); + return -1; + } + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetKeepAliveStatus +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetKeepAliveStatus( + bool& enabled, WebRtc_Word8& unknownPayloadType, + WebRtc_UWord16& deltaTransmitTimeMs) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + if (_rtpRtcp.RTPKeepaliveStatus(&enabled, &unknownPayloadType, + &deltaTransmitTimeMs) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not get RTP keepalive status", __FUNCTION__); + return -1; + } + WEBRTC_TRACE( + webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: enabled = %d, unknownPayloadType = %d, deltaTransmitTimeMs = %ul", + __FUNCTION__, enabled, (WebRtc_Word32) unknownPayloadType, + deltaTransmitTimeMs); + + return 0; +} + +// ---------------------------------------------------------------------------- +// StartRTPDump +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::StartRTPDump(const char fileNameUTF8[1024], + RTPDirections direction) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (direction != kRtpIncoming && direction != kRtpOutgoing) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: invalid input", + __FUNCTION__); + return -1; + } + RtpDump* rtpDump = NULL; + if (direction == kRtpIncoming) + { + return _vieReceiver.StartRTPDump(fileNameUTF8); + } + else + { + return _vieSender.StartRTPDump(fileNameUTF8); + } +} + +// ---------------------------------------------------------------------------- +// StopRTPDump +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::StopRTPDump(RTPDirections direction) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (direction != kRtpIncoming && direction != kRtpOutgoing) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: invalid input", + __FUNCTION__); + return -1; + } + RtpDump* rtpDump = NULL; + if (direction == kRtpIncoming) + { + return _vieReceiver.StopRTPDump(); + } + else + { + return _vieSender.StopRTPDump(); + } +} + +// ============================================================================ +// Network +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetLocalReceiver +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetLocalReceiver(const WebRtc_UWord16 rtpPort, + const WebRtc_UWord16 rtcpPort, + const WebRtc_Word8* ipAddress) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + _callbackCritsect.Enter(); + if (_ptrExternalTransport) + { + _callbackCritsect.Leave(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: external transport registered", __FUNCTION__); + return -1; + } + _callbackCritsect.Leave(); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.Receiving()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: already receiving", + __FUNCTION__); + return -1; + } + + const WebRtc_Word8* multicastIpAddress = NULL; + if (_socketTransport.InitializeReceiveSockets(&_vieReceiver, rtpPort, + ipAddress, + multicastIpAddress, rtcpPort) + != 0) + { + WebRtc_Word32 socketError = _socketTransport.LastError(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: could not initialize receive sockets. Socket error: %d", + __FUNCTION__, socketError); + return -1; + } + + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// GetLocalReceiver +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetLocalReceiver(WebRtc_UWord16& rtpPort, + WebRtc_UWord16& rtcpPort, + WebRtc_Word8* ipAddress) const +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + _callbackCritsect.Enter(); + if (_ptrExternalTransport) + { + _callbackCritsect.Leave(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: external transport registered", __FUNCTION__); + return -1; + } + _callbackCritsect.Leave(); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.ReceiveSocketsInitialized() == false) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: receive sockets not initialized", __FUNCTION__); + return -1; + } + + WebRtc_Word8 multicastIpAddress[UdpTransport:: + kIpAddressVersion6Length]; + if (_socketTransport.ReceiveSocketInformation(ipAddress, rtpPort, rtcpPort, + multicastIpAddress) != 0) + { + WebRtc_Word32 socketError = _socketTransport.LastError(); + WEBRTC_TRACE( + webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: could not get receive socket information. Socket error: %d", + __FUNCTION__, socketError); + return -1; + } + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// SetSendDestination +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetSendDestination( + const WebRtc_Word8* ipAddress, const WebRtc_UWord16 rtpPort, + const WebRtc_UWord16 rtcpPort, const WebRtc_UWord16 sourceRtpPort, + const WebRtc_UWord16 sourceRtcpPort) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + _callbackCritsect.Enter(); + if (_ptrExternalTransport) + { + _callbackCritsect.Leave(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: external transport registered", __FUNCTION__); + return -1; + } + _callbackCritsect.Leave(); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + const bool isIPv6 = _socketTransport.IpV6Enabled(); + if (UdpTransport::IsIpAddressValid(ipAddress, isIPv6) == false) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Not a valid IP address: %s", __FUNCTION__, ipAddress); + return -1; + } + if (_socketTransport.InitializeSendSockets(ipAddress, rtpPort, rtcpPort) + != 0) + { + WebRtc_Word32 socketError = _socketTransport.LastError(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: could not initialize send socket. Socket error: %d", + __FUNCTION__, socketError); + return -1; + } + + if (sourceRtpPort != 0) + { + WebRtc_UWord16 receiveRtpPort = 0; + WebRtc_UWord16 receiveRtcpPort = 0; + if (_socketTransport.ReceiveSocketInformation(NULL, receiveRtpPort, + receiveRtcpPort, NULL) + != 0) + { + WebRtc_Word32 socketError = _socketTransport.LastError(); + WEBRTC_TRACE( + webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: could not get receive port information. Socket error: %d", + __FUNCTION__, socketError); + return -1; + } + // Initialize an extra socket only if send port differs from receive + // port + if (sourceRtpPort != receiveRtpPort) + { + if (_socketTransport.InitializeSourcePorts(sourceRtpPort, + sourceRtcpPort) != 0) + { + WebRtc_Word32 socketError = _socketTransport.LastError(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: could not set source ports. Socket error: %d", + __FUNCTION__, socketError); + return -1; + } + } + } + _vieSender.RegisterSendTransport(&_socketTransport); + + // Workaround to avoid SSRC colision detection in loppback tests + if (!isIPv6) + { + WebRtc_UWord32 localHostAddress = 0; + const WebRtc_UWord32 currentIpAddress = + UdpTransport::InetAddrIPV4(ipAddress); + + if ((UdpTransport::LocalHostAddress(localHostAddress) == 0 + && localHostAddress == currentIpAddress) || + strncmp("127.0.0.1", ipAddress, 9) == 0) + { + _rtpRtcp.SetSSRC(0xFFFFFFFF); + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Running in loopback. Forcing fixed SSRC"); + } + } + else + { + WebRtc_UWord8 localHostAddress[16]; + WebRtc_UWord8 currentIpAddress[16]; + + WebRtc_Word32 convResult = + UdpTransport::LocalHostAddressIPV6(localHostAddress); + convResult + += _socketTransport.InetPresentationToNumeric(23, ipAddress, + currentIpAddress); + if (convResult == 0) + { + bool localHost = true; + for (WebRtc_Word32 i = 0; i < 16; i++) + { + if (localHostAddress[i] != currentIpAddress[i]) + { + localHost = false; + break; + } + } + if (!localHost) + { + localHost = true; + for (WebRtc_Word32 i = 0; i < 15; i++) + { + if (currentIpAddress[i] != 0) + { + localHost = false; + break; + } + } + if (localHost == true && currentIpAddress[15] != 1) + { + localHost = false; + } + } + if (localHost) + { + _rtpRtcp.SetSSRC(0xFFFFFFFF); + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Running in loopback. Forcing fixed SSRC"); + } + } + } + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// GetSendDestination +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetSendDestination( + WebRtc_Word8* ipAddress, WebRtc_UWord16& rtpPort, WebRtc_UWord16& rtcpPort, + WebRtc_UWord16& sourceRtpPort, WebRtc_UWord16& sourceRtcpPort) const +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + _callbackCritsect.Enter(); + if (_ptrExternalTransport) + { + _callbackCritsect.Leave(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: external transport registered", __FUNCTION__); + return -1; + } + _callbackCritsect.Leave(); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.SendSocketsInitialized() == false) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: send sockets not initialized", __FUNCTION__); + return -1; + } + if (_socketTransport.SendSocketInformation(ipAddress, rtpPort, rtcpPort) + != 0) + { + WebRtc_Word32 socketError = _socketTransport.LastError(); + WEBRTC_TRACE( + webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: could not get send socket information. Socket error: %d", + __FUNCTION__, socketError); + return -1; + } + sourceRtpPort = 0; + sourceRtcpPort = 0; + if (_socketTransport.SourcePortsInitialized()) + { + _socketTransport.SourcePorts(sourceRtpPort, sourceRtcpPort); + } + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// StartSend +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::StartSend() +{ + CriticalSectionScoped cs(_callbackCritsect); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (!_ptrExternalTransport) + { + if (_socketTransport.SendSocketsInitialized() == false) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId,_channelId), + "%s: send sockets not initialized", __FUNCTION__); + return -1; + } + } +#endif + _rtpRtcp.SetSendingMediaStatus(true); + + if (_rtpRtcp.Sending() && !_rtpRtcp.RTPKeepalive()) + { + if (_rtpRtcp.RTPKeepalive()) + { + // Sending Keep alive, don't trigger an error + return 0; + } + // Already sending + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Already sending", + __FUNCTION__); + return kViEBaseAlreadySending; + } + if (_rtpRtcp.SetSendingStatus(true) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not start sending RTP", __FUNCTION__); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// StopSend +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::StopSend() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + _rtpRtcp.SetSendingMediaStatus(false); + if (_rtpRtcp.RTPKeepalive()) + { + // Don't turn off sending since we'll send keep alive packets + return 0; + } + if (!_rtpRtcp.Sending()) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Not sending", + __FUNCTION__); + return kViEBaseNotSending; + } + // Reset + _rtpRtcp.ResetSendDataCountersRTP(); + if (_rtpRtcp.SetSendingStatus(false) != 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: could not stop RTP sending", __FUNCTION__); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// Sending +// ---------------------------------------------------------------------------- + +bool ViEChannel::Sending() +{ + return _rtpRtcp.Sending(); +} + +// ---------------------------------------------------------------------------- +// StartReceive +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::StartReceive() +{ + CriticalSectionScoped cs(_callbackCritsect); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (!_ptrExternalTransport) + { + if (_socketTransport.Receiving()) + { + // Warning, don't return error + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: already receiving", + __FUNCTION__); + return 0; + } + if (_socketTransport.ReceiveSocketsInitialized() == false) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: receive sockets not initialized", __FUNCTION__); + return -1; + } + if (_socketTransport.StartReceiving(kViENumReceiveSocketBuffers) + != 0) + { + WebRtc_Word32 socketError = _socketTransport.LastError(); + WEBRTC_TRACE( + webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: could not get receive socket information. Socket error:%d", + __FUNCTION__, socketError); + return -1; + } + } +#endif + if (StartDecodeThread() != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: could not start decoder thread", __FUNCTION__); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + _socketTransport.StopReceiving(); +#endif + _vieReceiver.StopReceive(); + return -1; + } + _vieReceiver.StartReceive(); + + return 0; +} + +// ---------------------------------------------------------------------------- +// StopReceive +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::StopReceive() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + _vieReceiver.StopReceive(); + StopDecodeThread(); + _vcm.ResetDecoder(); + { + CriticalSectionScoped cs(_callbackCritsect); + if (_ptrExternalTransport) + { + return 0; + } + } + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.Receiving() == false) + { + // Warning, don't return error + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: not receiving", + __FUNCTION__); + return 0; + } + if (_socketTransport.StopReceiving() != 0) + { + WebRtc_Word32 socketError = _socketTransport.LastError(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: Socket error: %d", __FUNCTION__, socketError); + return -1; + } +#endif + + return 0; +} + +bool ViEChannel::Receiving() +{ +#ifndef WEBRTC_EXTERNAL_TRANSPORT + return _socketTransport.Receiving(); +#else + return false; +#endif +} + +// ---------------------------------------------------------------------------- +// GetSourceInfo +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetSourceInfo(WebRtc_UWord16& rtpPort, + WebRtc_UWord16& rtcpPort, + WebRtc_Word8* ipAddress, + WebRtc_UWord32 ipAddressLength) +{ + { + CriticalSectionScoped cs(_callbackCritsect); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_ptrExternalTransport) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: external transport registered", __FUNCTION__); + return -1; + } + } +#ifndef WEBRTC_EXTERNAL_TRANSPORT + + if (_socketTransport.IpV6Enabled() && ipAddressLength + < UdpTransport::kIpAddressVersion6Length) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: IP address length is too small for IPv6", __FUNCTION__); + return -1; + } + else if (ipAddressLength < + UdpTransport::kIpAddressVersion4Length) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: IP address length is too small for IPv4", __FUNCTION__); + return -1; + } + + if (_socketTransport.RemoteSocketInformation(ipAddress, rtpPort, rtcpPort) + != 0) + { + WebRtc_Word32 socketError = _socketTransport.LastError(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Error getting source ports. Socket error: %d", + __FUNCTION__, socketError); + return -1; + } + + return 0; +#else + + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", + __FUNCTION__); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// RegisterSendTransport +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::RegisterSendTransport(Transport& transport) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.SendSocketsInitialized() + || _socketTransport.ReceiveSocketsInitialized()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: socket transport already initialized", + __FUNCTION__); + return -1; + } +#endif + + if (_rtpRtcp.Sending()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Sending", __FUNCTION__); + return -1; + } + + CriticalSectionScoped cs(_callbackCritsect); + if (_ptrExternalTransport) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: transport already registered", __FUNCTION__); + return -1; + } + _ptrExternalTransport = &transport; + _vieSender.RegisterSendTransport(&transport); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: Transport registered: 0x%p", __FUNCTION__, + &_ptrExternalTransport); + + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterSendTransport +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::DeregisterSendTransport() +{ + CriticalSectionScoped cs(_callbackCritsect); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_ptrExternalTransport == NULL) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: no transport registered", __FUNCTION__); + return -1; + } + if (_rtpRtcp.Sending()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Sending", __FUNCTION__); + return -1; + } + _ptrExternalTransport = NULL; + _vieSender.DeregisterSendTransport(); + return 0; +} + +// ---------------------------------------------------------------------------- +// ReceivedRTPPacket +// +// Incoming packet from external transport +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::ReceivedRTPPacket(const void* rtpPacket, + const WebRtc_Word32 rtpPacketLength) +{ + { + CriticalSectionScoped cs(_callbackCritsect); + if (!_ptrExternalTransport) + { + return -1; + } + } + return _vieReceiver.ReceivedRTPPacket(rtpPacket, rtpPacketLength); +} + +// ---------------------------------------------------------------------------- +// ReceivedRTPPacket +// +// Incoming packet from external transport +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::ReceivedRTCPPacket( + const void* rtcpPacket, const WebRtc_Word32 rtcpPacketLength) +{ + { + CriticalSectionScoped cs(_callbackCritsect); + if (!_ptrExternalTransport) + { + return -1; + } + } + return _vieReceiver.ReceivedRTCPPacket(rtcpPacket, rtcpPacketLength); +} + +// ---------------------------------------------------------------------------- +// EnableIPv6 +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::EnableIPv6() +{ + _callbackCritsect.Enter(); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_ptrExternalTransport) + { + _callbackCritsect.Leave(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: External transport registered", __FUNCTION__); + return -1; + } + _callbackCritsect.Leave(); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.IpV6Enabled()) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: IPv6 already enabled", __FUNCTION__); + return -1; + } + + if (_socketTransport.EnableIpV6() != 0) + { + WebRtc_Word32 socketError = _socketTransport.LastError(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: could not enable IPv6. Socket error: %d", __FUNCTION__, + socketError); + return -1; + } + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif + +} + +// ---------------------------------------------------------------------------- +// IsIPv6Enabled +// ---------------------------------------------------------------------------- + +bool ViEChannel::IsIPv6Enabled() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + { + CriticalSectionScoped cs(_callbackCritsect); + if (_ptrExternalTransport) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: External transport registered", __FUNCTION__); + return false; + } + } +#ifndef WEBRTC_EXTERNAL_TRANSPORT + return _socketTransport.IpV6Enabled(); +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return false; +#endif +} + +// ---------------------------------------------------------------------------- +// SetSourceFilter +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetSourceFilter(const WebRtc_UWord16 rtpPort, + const WebRtc_UWord16 rtcpPort, + const WebRtc_Word8* ipAddress) +{ + _callbackCritsect.Enter(); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_ptrExternalTransport) + { + _callbackCritsect.Leave(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: External transport registered", __FUNCTION__); + return -1; + } + _callbackCritsect.Leave(); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.SetFilterIP(ipAddress) != 0) + { + // Logging done in module + return -1; + } + if (_socketTransport.SetFilterPorts(rtpPort, rtcpPort) != 0) + { + // Logging done + return -1; + } + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// GetSourceFilter +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetSourceFilter(WebRtc_UWord16& rtpPort, + WebRtc_UWord16& rtcpPort, + WebRtc_Word8* ipAddress) const +{ + _callbackCritsect.Enter(); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_ptrExternalTransport) + { + _callbackCritsect.Leave(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: External transport registered", __FUNCTION__); + return -1; + } + _callbackCritsect.Leave(); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.FilterIP(ipAddress) != 0) + { + // Logging done in module + return -1; + } + if (_socketTransport.FilterPorts(rtpPort, rtcpPort) != 0) + { + // Logging done in module + return -1; + } + + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// SetToS +// ---------------------------------------------------------------------------- + +// ToS +WebRtc_Word32 ViEChannel::SetToS(const WebRtc_Word32 DSCP, + const bool useSetSockOpt) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + { + CriticalSectionScoped cs(_callbackCritsect); + if (_ptrExternalTransport) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: External transport registered", __FUNCTION__); + return -1; + } + } +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.SetToS(DSCP, useSetSockOpt) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Socket error: %d", + __FUNCTION__, _socketTransport.LastError()); + return -1; + } + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// GetToS +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetToS(WebRtc_Word32& DSCP, bool& useSetSockOpt) const +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + { + CriticalSectionScoped cs(_callbackCritsect); + if (_ptrExternalTransport) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: External transport registered", __FUNCTION__); + return -1; + } + } +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.ToS(DSCP, useSetSockOpt) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Socket error: %d", + __FUNCTION__, _socketTransport.LastError()); + return -1; + } + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// SetSendGQoS +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetSendGQoS(const bool enable, + const WebRtc_Word32 serviceType, + const WebRtc_UWord32 maxBitrate, + const WebRtc_Word32 overrideDSCP) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + { + CriticalSectionScoped cs(_callbackCritsect); + if (_ptrExternalTransport) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: External transport registered", __FUNCTION__); + return -1; + } + } +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.SetQoS(enable, serviceType, maxBitrate, overrideDSCP, + false) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Socket error: %d", + __FUNCTION__, _socketTransport.LastError()); + return -1; + } + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// GetSendGQoS +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::GetSendGQoS(bool& enabled, + WebRtc_Word32& serviceType, + WebRtc_Word32& overrideDSCP) const +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + { + CriticalSectionScoped cs(_callbackCritsect); + if (_ptrExternalTransport) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: External transport registered", __FUNCTION__); + return -1; + } + } +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.QoS(enabled, serviceType, overrideDSCP) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Socket error: %d", + __FUNCTION__, _socketTransport.LastError()); + return -1; + } + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// SetMTU +// +// Sets the maximum transfer unit size for the network link, i.e. including +// IP, UDP[/TCP] and RTP headers, +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetMTU(WebRtc_UWord16 mtu) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_rtpRtcp.SetMaxTransferUnit(mtu) != 0) + { + // Logging done + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetMaxDataPayloadLength +// +// maxDataPayloadLength: maximum allowed payload size, i.e. the maximum +// allowed size of encoded data in each packet. +// ---------------------------------------------------------------------------- + +WebRtc_UWord16 ViEChannel::MaxDataPayloadLength() const +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + return _rtpRtcp.MaxDataPayloadLength(); +} + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// SetPacketTimeoutNotification +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::SetPacketTimeoutNotification( + bool enable, + WebRtc_UWord32 timeoutSeconds) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (enable) + { + WebRtc_UWord32 timeoutMs = 1000 * timeoutSeconds; + if (_rtpRtcp.SetPacketTimeout(timeoutMs, 0) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s", + __FUNCTION__); + return -1; + } + } + else + { + if (_rtpRtcp.SetPacketTimeout(0, 0) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId,_channelId), "%s", + __FUNCTION__); + return -1; + } + } + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterObserver +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::RegisterNetworkObserver( + ViENetworkObserver* observer) +{ + CriticalSectionScoped cs(_callbackCritsect); + if (observer) + { + if (_networkObserver) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: observer alread added", __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: observer added", __FUNCTION__); + _networkObserver = observer; + } + else + { + if (!_networkObserver) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: no observer added", + __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: observer removed", __FUNCTION__); + _networkObserver = NULL; + } + return 0; +} +bool ViEChannel::NetworkObserverRegistered() +{ + CriticalSectionScoped cs(_callbackCritsect); + return _networkObserver != NULL; +} + +// ---------------------------------------------------------------------------- +// SetPeriodicDeadOrAliveStatus +// ---------------------------------------------------------------------------- +WebRtc_Word32 ViEChannel::SetPeriodicDeadOrAliveStatus( + const bool enable, const WebRtc_UWord32 sampleTimeSeconds) +{ + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + CriticalSectionScoped cs(_callbackCritsect); + if (_networkObserver == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: no observer added", __FUNCTION__); + return -1; + } + + bool enabled = false; + WebRtc_UWord8 currentSampletimeSeconds = 0; + + // Get old settings + _rtpRtcp.PeriodicDeadOrAliveStatus(enabled, currentSampletimeSeconds); + // Set new settings + if (_rtpRtcp.SetPeriodicDeadOrAliveStatus( + enable, (WebRtc_UWord8) sampleTimeSeconds) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not set periodic dead-or-alive status", + __FUNCTION__); + return -1; + } + if (!enable) + { + // Restore last utilized sample time. + // Without this trick, the sample time would always be reset to default + // (2 sec), each time dead-or-alive was disabled without sample-time + // parameter. + _rtpRtcp.SetPeriodicDeadOrAliveStatus(enable, currentSampletimeSeconds); + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// SendUDPPacket +// ---------------------------------------------------------------------------- +WebRtc_Word32 ViEChannel::SendUDPPacket(const WebRtc_Word8* data, + const WebRtc_UWord32 length, + WebRtc_Word32& transmittedBytes, + bool useRtcpSocket) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + { + CriticalSectionScoped cs(_callbackCritsect); + if (_ptrExternalTransport) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: External transport registered", __FUNCTION__); + return -1; + } + } +#ifndef WEBRTC_EXTERNAL_TRANSPORT + transmittedBytes = _socketTransport.SendRaw(data, length, useRtcpSocket); + if (transmittedBytes == -1) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s", __FUNCTION__); + return -1; + } + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: not available for external transport", __FUNCTION__); + return -1; +#endif +} + +// ============================================================================ +// Color enahncement +// ============================================================================ + +// ---------------------------------------------------------------------------- +// EnableColorEnhancement +// +// Enables/disables color enhancement for all decoded frames +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::EnableColorEnhancement(bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(enable: %d)", __FUNCTION__, enable); + + CriticalSectionScoped cs(_callbackCritsect); + if (enable && _colorEnhancement) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Already enabled", + __FUNCTION__); + return -1; + } + else if (enable == false && _colorEnhancement == false) + + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: not enabled", + __FUNCTION__); + return -1; + } + _colorEnhancement = enable; + return 0; +} + +// ============================================================================ +// Register sender +// ============================================================================ + +// ---------------------------------------------------------------------------- +// RegisterSendRtpRtcpModule +// +// Register send RTP RTCP module, which will deliver the frames to send +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::RegisterSendRtpRtcpModule( + RtpRtcp& sendRtpRtcpModule) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + return _rtpRtcp.RegisterDefaultModule(&sendRtpRtcpModule); +} + +// ---------------------------------------------------------------------------- +// RegisterSendDeregisterSendRtpRtcpModuleRtpRtcpModule +// +// Deregisters the send RTP RTCP module, which will stop the encoder input to +// the channel +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::DeregisterSendRtpRtcpModule() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + return _rtpRtcp.DeRegisterDefaultModule(); +} + +// ============================================================================ +// FrameToRender +// Called by VCM when a frame have been decoded. +// ============================================================================ + +WebRtc_Word32 ViEChannel::FrameToRender(VideoFrame& videoFrame) +{ + CriticalSectionScoped cs(_callbackCritsect); + + if (_decoderReset) + { + // Trigger a callback to the user if the incoming codec has changed. + if (_codecObserver) + { + VideoCodec decoder; + memset(&decoder, 0, sizeof(decoder)); + if (_vcm.ReceiveCodec(&decoder) == VCM_OK) + { + // VCM::ReceiveCodec returns the codec set by + // RegisterReceiveCodec, which might not be the size we're + // actually decoding + decoder.width = (unsigned short) videoFrame.Width(); + decoder.height = (unsigned short) videoFrame.Height(); + _codecObserver->IncomingCodecChanged(_channelId, decoder); + } + else + { + assert(false); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not get receive codec", __FUNCTION__); + } + } + _decoderReset = false; + } + if (_effectFilter) + { + _effectFilter->Transform(videoFrame.Length(), videoFrame.Buffer(), + videoFrame.TimeStamp(), videoFrame.Width(), + videoFrame.Height()); + } + if (_colorEnhancement) + { + VideoProcessingModule::ColorEnhancement(videoFrame); + } + + // Record videoframe + _fileRecorder.RecordVideoFrame(videoFrame); + + WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]; + WebRtc_Word32 noOfCSRCs = _rtpRtcp.RemoteCSRCs(arrOfCSRC); + if (noOfCSRCs <= 0) + { + arrOfCSRC[0] = _rtpRtcp.RemoteSSRC(); + noOfCSRCs = 1; + } + + DeliverFrame(videoFrame, noOfCSRCs, arrOfCSRC); + + return 0; +} + +WebRtc_Word32 ViEChannel::ReceivedDecodedReferenceFrame( + const WebRtc_UWord64 pictureId) +{ + return _rtpRtcp.SendRTCPReferencePictureSelection(pictureId); +} + +// ============================================================================ +// StoreReceivedFrame +// Called by VCM before a frame have been decoded. could be used for recording +// incoming video. +// ============================================================================ + +WebRtc_Word32 ViEChannel::StoreReceivedFrame( + const EncodedVideoData& frameToStore) +{ + return 0; +} + +// ---------------------------------------------------------------------------- +// ReceiveStatistics +// +// Called by VCM with information about received video stream +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::ReceiveStatistics(const WebRtc_UWord32 bitRate, + const WebRtc_UWord32 frameRate) +{ + CriticalSectionScoped cs(_callbackCritsect); + if (_codecObserver) + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: bitrate %u, framerate %u", __FUNCTION__, bitRate, + frameRate); + _codecObserver->IncomingRate(_channelId, frameRate, bitRate); + } + return 0; +} + +// ---------------------------------------------------------------------------- +// FrameTypeRequest +// +// Called by VCM when a certain frame type is needed to continue decoding +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::FrameTypeRequest(const FrameType frameType) +{ + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(frameType: %d)", __FUNCTION__, frameType); + + { + CriticalSectionScoped cs(_callbackCritsect); + if (_codecObserver && _doKeyFrameCallbackRequest) + { + _codecObserver->RequestNewKeyFrame(_channelId); + } + } + return _rtpRtcp.RequestKeyFrame(frameType); +} + +WebRtc_Word32 ViEChannel::SliceLossIndicationRequest( + const WebRtc_UWord64 pictureId) +{ + return _rtpRtcp.SendRTCPSliceLossIndication((WebRtc_UWord8) pictureId); +} + +// ---------------------------------------------------------------------------- +// ResendPackets +// +// Called by VCM when VCM wants to request resend of packets (NACK) +// ---------------------------------------------------------------------------- +WebRtc_Word32 ViEChannel::ResendPackets(const WebRtc_UWord16* sequenceNumbers, + WebRtc_UWord16 length) +{ + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(length: %d)", __FUNCTION__, length); + + return _rtpRtcp.SendNACK(sequenceNumbers, length); +} + +// ============================================================================ +// Protected methods +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ChannelDecodeThreadFunction +// ---------------------------------------------------------------------------- + +bool ViEChannel::ChannelDecodeThreadFunction(void* obj) +{ + return static_cast (obj)->ChannelDecodeProcess(); +} + +// ---------------------------------------------------------------------------- +// ChannelDecodeThreadFunction +// ---------------------------------------------------------------------------- + +bool ViEChannel::ChannelDecodeProcess() +{ + // Decode is blocking, but sleep some time anyway to not get a spin + _vcm.Decode(50); + + if ((TickTime::Now() - _vcmRTTReported).Milliseconds() > 1000) + { + WebRtc_UWord16 RTT; + WebRtc_UWord16 avgRTT; + WebRtc_UWord16 minRTT; + WebRtc_UWord16 maxRTT; + + if (_rtpRtcp.RTT(_rtpRtcp.RemoteSSRC(), &RTT, &avgRTT, &minRTT, &maxRTT) + == 0) + { + _vcm.SetReceiveChannelParameters(RTT); + } + _vcmRTTReported = TickTime::Now(); + } + return true; +} + +// ============================================================================ +// Private methods +// ============================================================================ + +// ---------------------------------------------------------------------------- +// StartDecodeThread +// +// Assumed to be critsect protected if needed +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::StartDecodeThread() +{ + // Start the decode thread + if (_ptrDecodeThread) + { + // Already started + return 0; + } + _ptrDecodeThread = ThreadWrapper::CreateThread(ChannelDecodeThreadFunction, + this, kHighestPriority, + "DecodingThread"); + if (_ptrDecodeThread == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: could not create decode thread", __FUNCTION__); + return -1; + } + + unsigned int threadId; + if (_ptrDecodeThread->Start(threadId) == false) + { + delete _ptrDecodeThread; + _ptrDecodeThread = NULL; + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: could not start decode thread", __FUNCTION__); + return -1; + } + + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: decode thread with id %u started", __FUNCTION__); + return 0; +} + +// ---------------------------------------------------------------------------- +// StopDecodeThread +// +// Assumed to be critsect protected if needed +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEChannel::StopDecodeThread() +{ + if (_ptrDecodeThread == NULL) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: decode thread not running", __FUNCTION__); + return 0; + } + + _ptrDecodeThread->SetNotAlive(); + if (_ptrDecodeThread->Stop()) + { + delete _ptrDecodeThread; + } + else + { + // Couldn't stop the thread, leak instead of crash... + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: could not stop decode thread", __FUNCTION__); + assert(!"could not stop decode thread"); + } + _ptrDecodeThread = NULL; + return 0; +} + +#ifdef WEBRTC_SRTP + +WebRtc_Word32 +ViEChannel::EnableSRTPSend(const SrtpModule::CipherTypes cipherType, + const unsigned int cipherKeyLength, + const SrtpModule::AuthenticationTypes authType, + const unsigned int authKeyLength, const unsigned int authTagLength, + const SrtpModule::SecurityLevels level, const WebRtc_UWord8* key, + const bool useForRTCP) +{ + + _callbackCritsect.Enter(); + if (_ptrExternalEncryption) + { + _callbackCritsect.Leave(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: external encryption already registered", __FUNCTION__); + return -1; + } + _callbackCritsect.Leave(); + + if (!_ptrSrtpModuleEncryption) + { + _ptrSrtpModuleEncryption = + SrtpModule::CreateSrtpModule( + ViEModuleId(_engineId, _channelId)); + if(!_ptrSrtpModuleEncryption) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Failed to create SRTP module"); + return -1; + } + } + + const WebRtc_Word32 result = + _ptrSrtpModuleEncryption->EnableSRTPEncrypt( + !useForRTCP, cipherType, cipherKeyLength, authType, authKeyLength, + authTagLength,level,key); + if (0 != result) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "EnableSRTPEncrypt result %d, Apply To RTCP %d", result, + useForRTCP); + } + else + { + _vieSender.RegisterSRTPModule(_ptrSrtpModuleEncryption); + if (useForRTCP) + { + _vieSender.RegisterSRTCPModule(_ptrSrtpModuleEncryption); + } + } + return result; +} + +WebRtc_Word32 ViEChannel::DisableSRTPSend() +{ + WebRtc_Word32 result = -1; + if (_ptrSrtpModuleEncryption) + { + result = _ptrSrtpModuleEncryption->DisableSRTPEncrypt(); + _vieSender.DeregisterSRTPModule(); + _vieSender.DeregisterSRTCPModule(); + } + +} + +WebRtc_Word32 +ViEChannel::EnableSRTPReceive(const SrtpModule::CipherTypes cipherType, + const unsigned int cipherKeyLength, + const SrtpModule::AuthenticationTypes authType, + const unsigned int authKeyLength, const unsigned int authTagLength, + const SrtpModule::SecurityLevels level, const WebRtc_UWord8* key, + const bool useForRTCP) +{ + _callbackCritsect.Enter(); + if (_ptrExternalEncryption) + { + _callbackCritsect.Leave(); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: external encryption already registered", __FUNCTION__); + return -1; + } + _callbackCritsect.Leave(); + + if (!_ptrSrtpModuleDecryption) + { + _ptrSrtpModuleDecryption = + SrtpModule::CreateSrtpModule( + ViEModuleId(_engineId, _channelId)); + if(!_ptrSrtpModuleDecryption) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Failed to create SRTP module"); + return -1; + } + } + + const WebRtc_Word32 result = + _ptrSrtpModuleDecryption->EnableSRTPDecrypt( + !useForRTCP, cipherType, cipherKeyLength, authType, authKeyLength, + authTagLength,level,key); + if (0 != result) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "EnableSRTPEncrypt result %d, Apply To RTCP %d", result, + useForRTCP); + } + else + { + _vieReceiver.RegisterSRTPModule(_ptrSrtpModuleDecryption); + if (useForRTCP) + { + _vieReceiver.RegisterSRTCPModule(_ptrSrtpModuleDecryption); + } + } + return result; +} + +WebRtc_Word32 ViEChannel::DisableSRTPReceive() +{ + WebRtc_Word32 result = -1; + if (_ptrSrtpModuleDecryption) + { + result = _ptrSrtpModuleDecryption->DisableSRTPDecrypt(); + _vieReceiver.DeregisterSRTPModule(); + _vieReceiver.DeregisterSRTPModule(); + } + return result; +} +#endif + +WebRtc_Word32 ViEChannel::RegisterExternalEncryption( + Encryption* encryption) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + CriticalSectionScoped cs(_callbackCritsect); + if (_ptrExternalEncryption) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: external encryption already registered", __FUNCTION__); + return -1; + } + + _ptrExternalEncryption = encryption; + + _vieReceiver.RegisterExternalDecryption(encryption); + _vieSender.RegisterExternalEncryption(encryption); + + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", "external encryption object registerd with channel=%d", + _channelId); + return 0; +} + +WebRtc_Word32 ViEChannel::DeRegisterExternalEncryption() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + CriticalSectionScoped cs(_callbackCritsect); + if (!_ptrExternalEncryption) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: external encryption is not registered", __FUNCTION__); + return -1; + } + + _ptrExternalTransport = NULL; + _vieReceiver.DeregisterExternalDecryption(); + _vieSender.DeregisterExternalEncryption(); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s external encryption object de-registerd with channel=%d", + __FUNCTION__, _channelId); + return 0; +} + +WebRtc_Word32 ViEChannel::SetVoiceChannel(WebRtc_Word32 veChannelId, + VoEVideoSync* veSyncInterface) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s, audio channel %d, video channel %d", __FUNCTION__, + veChannelId, _channelId); + + if (veSyncInterface) + { + // Register lip sync + _moduleProcessThread.RegisterModule(&_vieSync); + } + else + { + _moduleProcessThread.DeRegisterModule(&_vieSync); + } + return _vieSync.SetVoiceChannel(veChannelId, veSyncInterface); +} + +WebRtc_Word32 ViEChannel::VoiceChannel() +{ + return _vieSync.VoiceChannel(); +} + +WebRtc_Word32 ViEChannel::RegisterEffectFilter(ViEEffectFilter* effectFilter) +{ + CriticalSectionScoped cs(_callbackCritsect); + if (effectFilter == NULL) + { + if (_effectFilter == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: no effect filter added for channel %d", + __FUNCTION__, _channelId); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: deregister effect filter for device %d", __FUNCTION__, + _channelId); + } + else + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: register effect filter for device %d", __FUNCTION__, + _channelId); + if (_effectFilter) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: effect filter already added for channel %d", + __FUNCTION__, _channelId); + return -1; + } + } + _effectFilter = effectFilter; + return 0; +} + +ViEFileRecorder& ViEChannel::GetIncomingFileRecorder() +{ + // Start getting callback of all frames before they are decoded + _vcm.RegisterFrameStorageCallback(this); + return _fileRecorder; +} + +void ViEChannel::ReleaseIncomingFileRecorder() +{ + // Stop getting callback of all frames before they are decoded + _vcm.RegisterFrameStorageCallback(NULL); +} + +void ViEChannel::OnLipSyncUpdate(const WebRtc_Word32 id, + const WebRtc_Word32 audioVideoOffset) +{ + if (_channelId != ChannelId(id)) + { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s, incorrect id", + __FUNCTION__, id); + return; + } + _vieSync.SetNetworkDelay(audioVideoOffset); +} + +void ViEChannel::OnApplicationDataReceived(const WebRtc_Word32 id, + const WebRtc_UWord8 subType, + const WebRtc_UWord32 name, + const WebRtc_UWord16 length, + const WebRtc_UWord8* data) +{ + if (_channelId != ChannelId(id)) + { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s, incorrect id", + __FUNCTION__, id); + return; + } + CriticalSectionScoped cs(_callbackCritsect); + { + if (_rtcpObserver) + { + _rtcpObserver->OnApplicationDataReceived(_channelId, subType, name, + (const char*) data, length); + } + } +} + +WebRtc_Word32 ViEChannel::OnInitializeDecoder( + const WebRtc_Word32 id, const WebRtc_Word8 payloadType, + const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE], + const WebRtc_UWord32 frequency, const WebRtc_UWord8 channels, + const WebRtc_UWord32 rate) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: payloadType %d, payloadName %s", __FUNCTION__, payloadType, + payloadName); + + _vcm.ResetDecoder(); + + _callbackCritsect.Enter(); + _decoderReset = true; + _callbackCritsect.Leave(); + + return 0; +} + +void ViEChannel::OnPacketTimeout(const WebRtc_Word32 id) +{ + assert(ChannelId(id) == _channelId); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + CriticalSectionScoped cs(_callbackCritsect); + if (_networkObserver) + { +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (_socketTransport.Receiving() || _ptrExternalTransport) +#else + if (_ptrExternalTransport) +#endif + { + _networkObserver->PacketTimeout(_channelId, NoPacket); + _rtpPacketTimeout = true; + } + } +} + +// +// Called by the rtp module when the first packet is received and +// when first packet after a timeout is received. +// +void ViEChannel::OnReceivedPacket(const WebRtc_Word32 id, + const RtpRtcpPacketType packetType) +{ + assert(ChannelId(id) == _channelId); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_rtpPacketTimeout && packetType == kPacketRtp) + { + CriticalSectionScoped cs(_callbackCritsect); + if (_networkObserver) + { + _networkObserver->PacketTimeout(_channelId, PacketReceived); + } + // Reset even if no observer set, might have been removed during timeout + _rtpPacketTimeout = false; + } +} + +void ViEChannel::OnPeriodicDeadOrAlive(const WebRtc_Word32 id, + const RTPAliveType alive) +{ + assert(ChannelId(id) == _channelId); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(id=%d, alive=%d)", __FUNCTION__, id, alive); + + CriticalSectionScoped cs(_callbackCritsect); + if (!_networkObserver) + { + return; + } + bool isAlive = true; + if (alive == kRtpDead) + { + isAlive = false; + } + _networkObserver->OnPeriodicDeadOrAlive(_channelId, isAlive); + return; +} + +void ViEChannel::OnIncomingSSRCChanged(const WebRtc_Word32 id, + const WebRtc_UWord32 SSRC) +{ + if (_channelId != ChannelId(id)) + { + assert(false); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s, incorrect id", __FUNCTION__, id); + return; + } + + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: %u", __FUNCTION__, SSRC); + + CriticalSectionScoped cs(_callbackCritsect); + { + if (_rtpObserver) + { + _rtpObserver->IncomingSSRCChanged(_channelId, SSRC); + } + } +} + +void ViEChannel::OnIncomingCSRCChanged(const WebRtc_Word32 id, + const WebRtc_UWord32 CSRC, + const bool added) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: %u added: %d", __FUNCTION__, CSRC, added); + + if (_channelId != ChannelId(id)) + { + assert(false); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s, incorrect id", __FUNCTION__, id); + return; + } + + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: %u", __FUNCTION__, CSRC); + + CriticalSectionScoped cs(_callbackCritsect); + { + if (_rtpObserver) + { + _rtpObserver->IncomingCSRCChanged(_channelId, CSRC, added); + } + } +} + +WebRtc_Word32 ViEChannel::SetInverseH263Logic(const bool enable) +{ + return _rtpRtcp.SetH263InverseLogic(enable); +} + +} // namespace webrtc diff --git a/video_engine/main/source/vie_channel.h b/video_engine/main/source/vie_channel.h new file mode 100644 index 0000000000..c4908dbfb7 --- /dev/null +++ b/video_engine/main/source/vie_channel.h @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_channel.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CHANNEL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CHANNEL_H_ + +// Defines +#include "vie_defines.h" + +#include "typedefs.h" +#include "vie_network.h" +#include "rtp_rtcp_defines.h" +#include "udp_transport.h" +#include "video_coding_defines.h" +#ifdef WEBRTC_SRTP +#include "SrtpModule.h" +#endif +#include "tick_util.h" +#include "vie_frame_provider_base.h" +#include "vie_file_recorder.h" + +// Forward declarations + +class SrtpModule; +class VideoRenderCallback; + +namespace webrtc +{ +class CriticalSectionWrapper; +class Encryption; +class ProcessThread; +class RtpRtcp; +class ThreadWrapper; +class VideoCodingModule; +class VideoDecoder; +class ViEDecoderObserver; +class ViEEffectFilter; +class ViENetworkObserver; +class ViEReceiver; +class ViERTCPObserver; +class ViERTPObserver; +class ViESender; +class ViESyncModule; +class VoEVideoSync; + +class ViEChannel: + public VCMFrameTypeCallback, // VCM Module + public VCMReceiveCallback, // VCM Module + public VCMReceiveStatisticsCallback, // VCM Module + public VCMPacketRequestCallback, // VCM Module + public VCMFrameStorageCallback, // VCM Module + public RtcpFeedback, // RTP/RTCP Module + public RtpFeedback, // RTP/RTCP Module + public ViEFrameProviderBase +{ +public: + ViEChannel(WebRtc_Word32 channelId, WebRtc_Word32 engineId, + WebRtc_UWord32 numberOfCores, + ProcessThread& moduleProcessThread); + ~ViEChannel(); + + WebRtc_Word32 Init(); + + //----------------------------------------------------------------- + // Codecs + //----------------------------------------------------------------- + + WebRtc_Word32 SetSendCodec(const VideoCodec& videoCodec, + bool newStream = true); + + WebRtc_Word32 SetReceiveCodec(const VideoCodec& videoCodec); + + WebRtc_Word32 GetReceiveCodec(VideoCodec& videoCodec); + + WebRtc_Word32 RegisterCodecObserver(ViEDecoderObserver* observer); + + WebRtc_Word32 RegisterExternalDecoder(const WebRtc_UWord8 plType, + VideoDecoder* decoder, + bool decoderRender, + WebRtc_Word32 renderDelay); + + WebRtc_Word32 DeRegisterExternalDecoder(const WebRtc_UWord8 plType); + + WebRtc_Word32 ReceiveCodecStatistics(WebRtc_UWord32& numKeyFrames, + WebRtc_UWord32& numDeltaFrames); + + WebRtc_Word32 WaitForKeyFrame(bool wait); + + WebRtc_Word32 SetSignalPacketLossStatus(bool enable, bool onlyKeyFrames); + + //----------------------------------------------------------------- + // RTP/RTCP + //----------------------------------------------------------------- + WebRtc_Word32 SetRTCPMode(const RTCPMethod rtcpMode); + + WebRtc_Word32 GetRTCPMode(RTCPMethod& rtcpMode); + + WebRtc_Word32 SetNACKStatus(const bool enable); + + WebRtc_Word32 SetFECStatus(const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC); + + WebRtc_Word32 + SetKeyFrameRequestMethod(const KeyFrameRequestMethod method); + + WebRtc_Word32 EnableTMMBR(const bool enable); + + WebRtc_Word32 EnableKeyFrameRequestCallback(const bool enable); + + WebRtc_Word32 SetSSRC(const WebRtc_UWord32 SSRC); + + WebRtc_Word32 GetLocalSSRC(WebRtc_UWord32& SSRC); + + WebRtc_Word32 GetRemoteSSRC(WebRtc_UWord32& SSRC); + + WebRtc_Word32 GetRemoteCSRC(unsigned int CSRCs[kRtpCsrcSize]); + + WebRtc_Word32 SetStartSequenceNumber(WebRtc_UWord16 sequenceNumber); + + WebRtc_Word32 SetRTCPCName(const WebRtc_Word8 rtcpCName[]); + + WebRtc_Word32 GetRTCPCName(WebRtc_Word8 rtcpCName[]); + + WebRtc_Word32 GetRemoteRTCPCName(WebRtc_Word8 rtcpCName[]); + + WebRtc_Word32 RegisterRtpObserver(ViERTPObserver* observer); + + WebRtc_Word32 RegisterRtcpObserver(ViERTCPObserver* observer); + + WebRtc_Word32 SendApplicationDefinedRTCPPacket( + const WebRtc_UWord8 subType, + WebRtc_UWord32 name, + const WebRtc_UWord8* data, + WebRtc_UWord16 dataLengthInBytes); + + WebRtc_Word32 GetSendRtcpStatistics(WebRtc_UWord16& fractionLost, + WebRtc_UWord32& cumulativeLost, + WebRtc_UWord32& extendedMax, + WebRtc_UWord32& jitterSamples, + WebRtc_Word32& rttMs); + + WebRtc_Word32 GetReceivedRtcpStatistics(WebRtc_UWord16& fractionLost, + WebRtc_UWord32& cumulativeLost, + WebRtc_UWord32& extendedMax, + WebRtc_UWord32& jitterSamples, + WebRtc_Word32& rttMs); + + WebRtc_Word32 GetRtpStatistics(WebRtc_UWord32& bytesSent, + WebRtc_UWord32& packetsSent, + WebRtc_UWord32& bytesReceived, + WebRtc_UWord32& packetsReceived) const; + + WebRtc_Word32 SetKeepAliveStatus(const bool enable, + const WebRtc_Word8 unknownPayloadType, + const WebRtc_UWord16 deltaTransmitTimeMS); + + WebRtc_Word32 GetKeepAliveStatus(bool& enable, + WebRtc_Word8& unknownPayloadType, + WebRtc_UWord16& deltaTransmitTimeMS); + + WebRtc_Word32 StartRTPDump(const char fileNameUTF8[1024], + RTPDirections direction); + + WebRtc_Word32 StopRTPDump(RTPDirections direction); + + // Implements RtcpFeedback + virtual void OnLipSyncUpdate(const WebRtc_Word32 id, + const WebRtc_Word32 audioVideoOffset); + + virtual void OnApplicationDataReceived(const WebRtc_Word32 id, + const WebRtc_UWord8 subType, + const WebRtc_UWord32 name, + const WebRtc_UWord16 length, + const WebRtc_UWord8* data); + + // Implements RtpFeedback + virtual WebRtc_Word32 OnInitializeDecoder( + const WebRtc_Word32 id, + const WebRtc_Word8 payloadType, + const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE], + const WebRtc_UWord32 frequency, + const WebRtc_UWord8 channels, + const WebRtc_UWord32 rate); + + virtual void OnPacketTimeout(const WebRtc_Word32 id); + + virtual void OnReceivedPacket(const WebRtc_Word32 id, + const RtpRtcpPacketType packetType); + + virtual void OnPeriodicDeadOrAlive(const WebRtc_Word32 id, + const RTPAliveType alive); + + virtual void OnIncomingSSRCChanged(const WebRtc_Word32 id, + const WebRtc_UWord32 SSRC); + + virtual void OnIncomingCSRCChanged(const WebRtc_Word32 id, + const WebRtc_UWord32 CSRC, + const bool added); + + //----------------------------------------------------------------- + // Network + //----------------------------------------------------------------- + + // Soure and destination + WebRtc_Word32 SetLocalReceiver(const WebRtc_UWord16 rtpPort, + const WebRtc_UWord16 rtcpPort, + const WebRtc_Word8* ipAddress); + + WebRtc_Word32 GetLocalReceiver(WebRtc_UWord16& rtpPort, + WebRtc_UWord16& rtcpPort, + WebRtc_Word8* ipAddress) const; + + WebRtc_Word32 SetSendDestination(const WebRtc_Word8* ipAddress, + const WebRtc_UWord16 rtpPort, + const WebRtc_UWord16 rtcpPort, + const WebRtc_UWord16 sourceRtpPort, + const WebRtc_UWord16 sourceRtcpPort); + + WebRtc_Word32 GetSendDestination(WebRtc_Word8* ipAddress, + WebRtc_UWord16& rtpPort, + WebRtc_UWord16& rtcpPort, + WebRtc_UWord16& sourceRtpPort, + WebRtc_UWord16& sourceRtcpPort) const; + + WebRtc_Word32 GetSourceInfo(WebRtc_UWord16& rtpPort, + WebRtc_UWord16& rtcpPort, + WebRtc_Word8* ipAddress, + WebRtc_UWord32 ipAddressLength); + + // Start/Stop Send/Receive + WebRtc_Word32 StartSend(); + WebRtc_Word32 StopSend(); + bool Sending(); + WebRtc_Word32 StartReceive(); + WebRtc_Word32 StopReceive(); + bool Receiving(); + + // External transport + WebRtc_Word32 RegisterSendTransport(Transport& transport); + + WebRtc_Word32 DeregisterSendTransport(); + + WebRtc_Word32 ReceivedRTPPacket(const void* rtpPacket, + const WebRtc_Word32 rtpPacketLength); + + WebRtc_Word32 ReceivedRTCPPacket(const void* rtcpPacket, + const WebRtc_Word32 rtcpPacketLength); + + // IPv6 + WebRtc_Word32 EnableIPv6(); + + bool IsIPv6Enabled(); + + // Source IP address and port filter + WebRtc_Word32 SetSourceFilter(const WebRtc_UWord16 rtpPort, + const WebRtc_UWord16 rtcpPort, + const WebRtc_Word8* ipAddress); + + WebRtc_Word32 GetSourceFilter(WebRtc_UWord16& rtpPort, + WebRtc_UWord16& rtcpPort, + WebRtc_Word8* ipAddress) const; + + // ToS + WebRtc_Word32 SetToS(const WebRtc_Word32 DSCP, const bool useSetSockOpt); + + WebRtc_Word32 GetToS(WebRtc_Word32& DSCP, bool& useSetSockOpt) const; + + // GQoS + WebRtc_Word32 SetSendGQoS(const bool enable, + const WebRtc_Word32 serviceType, + const WebRtc_UWord32 maxBitrate, + const WebRtc_Word32 overrideDSCP); + + WebRtc_Word32 GetSendGQoS(bool& enabled, WebRtc_Word32& serviceType, + WebRtc_Word32& overrideDSCP) const; + + // Network settings + WebRtc_Word32 SetMTU(WebRtc_UWord16 mtu); + + WebRtc_UWord16 MaxDataPayloadLength() const; + + WebRtc_Word32 SetMaxPacketBurstSize(WebRtc_UWord16 maxNumberOfPackets); + + WebRtc_Word32 SetPacketBurstSpreadState(bool enable, + const WebRtc_UWord16 framePeriodMS); + + // Packet timout notification + WebRtc_Word32 SetPacketTimeoutNotification(bool enable, + WebRtc_UWord32 timeoutSeconds); + + // Periodic dead-or-alive reports + WebRtc_Word32 RegisterNetworkObserver(ViENetworkObserver* observer); + bool NetworkObserverRegistered(); + + WebRtc_Word32 + SetPeriodicDeadOrAliveStatus(const bool enable, + const WebRtc_UWord32 sampleTimeSeconds); + + WebRtc_Word32 SendUDPPacket(const WebRtc_Word8* data, + const WebRtc_UWord32 length, + WebRtc_Word32& transmittedBytes, + bool useRtcpSocket); + + //----------------------------------------------------------------- + // Image processing + //----------------------------------------------------------------- + WebRtc_Word32 EnableColorEnhancement(bool enable); + + //----------------------------------------------------------------- + // Register sender + //----------------------------------------------------------------- + WebRtc_Word32 + RegisterSendRtpRtcpModule(RtpRtcp& sendRtpRtcpModule); + + WebRtc_Word32 DeregisterSendRtpRtcpModule(); + + // Implements VCM::VCMReceiveCallback, getting decoded frames from + // VCM. + virtual WebRtc_Word32 FrameToRender(VideoFrame& videoFrame); + + // Implements VCM::VCMReceiveCallback, getting info about decoded + // frames from VCM. + virtual WebRtc_Word32 ReceivedDecodedReferenceFrame( + const WebRtc_UWord64 pictureId); + + //Implements VCM::VideoFrameStorageCallback + virtual WebRtc_Word32 StoreReceivedFrame( + const EncodedVideoData& frameToStore); + + // Implements VCM::VideoReceiveStatisticsCallback + virtual WebRtc_Word32 ReceiveStatistics(const WebRtc_UWord32 bitRate, + const WebRtc_UWord32 frameRate); + + // Implements VCM::VideoFrameTypeCallback + virtual WebRtc_Word32 FrameTypeRequest(const FrameType frameType); + + // Implements VCM::VideoFrameTypeCallback + virtual WebRtc_Word32 SliceLossIndicationRequest( + const WebRtc_UWord64 pictureId); + + // Implements VCM::VideoPacketRequestCallback + virtual WebRtc_Word32 ResendPackets(const WebRtc_UWord16* sequenceNumbers, + WebRtc_UWord16 length); + +#ifdef WEBRTC_SRTP + //SRTP + WebRtc_Word32 EnableSRTPSend( + const SrtpModule::CipherTypes cipherType, + const unsigned int cipherKeyLength, + const SrtpModule::AuthenticationTypes authType, + const unsigned int authKeyLength, + const unsigned int authTagLength, + const SrtpModule::SecurityLevels level, + const WebRtc_UWord8* key, + const bool useForRTCP); + + WebRtc_Word32 DisableSRTPSend(); + + WebRtc_Word32 EnableSRTPReceive( + const SrtpModule::CipherTypes cipherType, + const unsigned int cipherKeyLength, + const SrtpModule::AuthenticationTypes authType, + const unsigned int authKeyLength, + const unsigned int authTagLength, + const SrtpModule::SecurityLevels level, + const WebRtc_UWord8* key, + const bool useForRTCP); + WebRtc_Word32 DisableSRTPReceive(); +#endif + + WebRtc_Word32 RegisterExternalEncryption(Encryption* encryption); + WebRtc_Word32 DeRegisterExternalEncryption(); + + //Voice Engine + WebRtc_Word32 SetVoiceChannel(WebRtc_Word32 veChannelId, + VoEVideoSync* veSyncInterface); + WebRtc_Word32 VoiceChannel(); + + //ViEFrameProviderBase + virtual int FrameCallbackChanged(){return -1;} + + // Effect filter + WebRtc_Word32 RegisterEffectFilter(ViEEffectFilter* effectFilter); + + WebRtc_Word32 SetInverseH263Logic(const bool enable); + + // File recording + ViEFileRecorder& GetIncomingFileRecorder(); + void ReleaseIncomingFileRecorder(); + +protected: + // Thread function according to ThreadWrapper + static bool ChannelDecodeThreadFunction(void* obj); + bool ChannelDecodeProcess(); + +private: + + WebRtc_Word32 StartDecodeThread(); + WebRtc_Word32 StopDecodeThread(); + + // General members + WebRtc_Word32 _channelId; + WebRtc_Word32 _engineId; + WebRtc_UWord32 _numberOfCores; + WebRtc_UWord8 _numSocketThreads; + + // Critical sections + // Used for all registered callbacks except rendering. + CriticalSectionWrapper& _callbackCritsect; + // Use the same as above instead a seperate? + CriticalSectionWrapper& _dataCritsect; + + // Owned modules/classes + RtpRtcp& _rtpRtcp; +#ifndef WEBRTC_EXTERNAL_TRANSPORT + UdpTransport& _socketTransport; +#endif + VideoCodingModule& _vcm; + ViEReceiver& _vieReceiver; + ViESender& _vieSender; + ViESyncModule& _vieSync;//Lip syncronization + + //Uses + ProcessThread& _moduleProcessThread; + ViEDecoderObserver* _codecObserver; + bool _doKeyFrameCallbackRequest; + ViERTPObserver* _rtpObserver; + ViERTCPObserver* _rtcpObserver; + ViENetworkObserver* _networkObserver; + bool _rtpPacketTimeout; + bool _usingPacketSpread; + + // Registered members + Transport* _ptrExternalTransport; + + // Codec + bool _decoderReset; + bool _waitForKeyFrame; + + // Decoder + ThreadWrapper* _ptrDecodeThread; + + //SRTP - using seperate pointers for encryption and decryption to support + // simultaneous operations. + SrtpModule* _ptrSrtpModuleEncryption; + SrtpModule* _ptrSrtpModuleDecryption; + Encryption* _ptrExternalEncryption; + + // Effect filter and color enhancement + ViEEffectFilter* _effectFilter; + bool _colorEnhancement; + + // Time when RTT time was last reported to VCM JB. + TickTime _vcmRTTReported; + + //Recording + ViEFileRecorder _fileRecorder; +}; + +} // namespace webrtc + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CHANNEL_H_ diff --git a/video_engine/main/source/vie_channel_manager.cc b/video_engine/main/source/vie_channel_manager.cc new file mode 100644 index 0000000000..7429c637c0 --- /dev/null +++ b/video_engine/main/source/vie_channel_manager.cc @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_channel_manager.cc + */ + +#include "vie_channel_manager.h" +#include "engine_configurations.h" +#include "vie_defines.h" + +#include "critical_section_wrapper.h" +#include "trace.h" +#include "vie_channel.h" +#include "vie_encoder.h" +#include "process_thread.h" + +// VoiceEngine +#include "voe_video_sync.h" + +namespace webrtc +{ + +ViEChannelManagerScoped::ViEChannelManagerScoped( + const ViEChannelManager& vieChannelManager) + : ViEManagerScopedBase(vieChannelManager) +{ +} + +ViEChannel* ViEChannelManagerScoped::Channel(int vieChannelId) const +{ + return static_cast + (_vieManager)->ViEChannelPtr(vieChannelId); +} +ViEEncoder* ViEChannelManagerScoped::Encoder(int vieChannelId) const +{ + return static_cast + (_vieManager)->ViEEncoderPtr(vieChannelId); +} + +bool ViEChannelManagerScoped::ChannelUsingViEEncoder(int channelId) const +{ + return (static_cast + (_vieManager))->ChannelUsingViEEncoder( channelId); +} + +// ============================================================================ +// VieChannelManager +// ============================================================================ + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViEChannelManager::ViEChannelManager(int engineId, + int numberOfCores, + ViEPerformanceMonitor& viePerformanceMonitor) + : _ptrChannelIdCritsect(CriticalSectionWrapper::CreateCriticalSection()), + _engineId(engineId), _numberOfCores(numberOfCores), + _viePerformanceMonitor(viePerformanceMonitor), _channelMap(), + _freeChannelIds(new bool[kViEMaxNumberOfChannels]), + _freeChannelIdsSize(kViEMaxNumberOfChannels), _vieEncoderMap(), + _voiceSyncInterface(NULL), _voiceEngine(NULL), + _moduleProcessThread(NULL) +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(engineId), + "ViEChannelManager::ViEChannelManager(engineId: %d) - Constructor", + engineId); + + for (int idx = 0; idx < _freeChannelIdsSize; idx++) + { + _freeChannelIds[idx] = true; + } +} +// ---------------------------------------------------------------------------- +// SetModuleProcessThread +// Initialize the thread context used by none time critical tasks in video channels. +// ---------------------------------------------------------------------------- +void ViEChannelManager::SetModuleProcessThread( ProcessThread& moduleProcessThread) +{ + assert(!_moduleProcessThread); + _moduleProcessThread = &moduleProcessThread; +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViEChannelManager::~ViEChannelManager() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(_engineId), + "ViEChannelManager Destructor, engineId: %d", _engineId); + + while (_channelMap.Size() != 0) + { + MapItem* item = _channelMap.First(); + const int channelId = item->GetId(); + item = NULL; + DeleteChannel(channelId); + } + + if (_voiceSyncInterface) + _voiceSyncInterface->Release(); + if (_ptrChannelIdCritsect) + { + delete _ptrChannelIdCritsect; + _ptrChannelIdCritsect = NULL; + } + if (_freeChannelIds) + { + delete[] _freeChannelIds; + _freeChannelIds = NULL; + _freeChannelIdsSize = 0; + } +} + +// ---------------------------------------------------------------------------- +// CreateChannel +// +// Creates a new channel. 'channelId' will be the id of the created channel +// ---------------------------------------------------------------------------- +int ViEChannelManager::CreateChannel(int& channelId) +{ + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + + // Get a free id for the new channel + if (GetFreeChannelId(channelId) == false) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "Max number of channels reached: %d", _channelMap.Size()); + return -1; + } + + ViEChannel* vieChannel = new ViEChannel(channelId, _engineId, + _numberOfCores, + *_moduleProcessThread); + if (vieChannel == NULL) + { + ReturnChannelId(channelId); + return -1; + } + if (vieChannel->Init() != 0) + { + // Could not init channel + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s could not init channel", __FUNCTION__, channelId); + ReturnChannelId(channelId); + delete vieChannel; + vieChannel = NULL; + return -1; + + } + // There is no ViEEncoder for this channel, create one with default settings + ViEEncoder* vieEncoder = new ViEEncoder(_engineId, channelId, + _numberOfCores, + *_moduleProcessThread); + if (vieEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s(videoChannelId: %d) - Could not create a new encoder", + __FUNCTION__, channelId); + delete vieChannel; + return -1; + } + + // Add to the map + if (_vieEncoderMap.Insert(channelId, vieEncoder) != 0) + { + // Could not add to the map + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could not add new encoder for video channel %d", + __FUNCTION__, channelId); + delete vieChannel; + delete vieEncoder; + return -1; + } + _channelMap.Insert(channelId, vieChannel); + // Register the channel at the encoder + RtpRtcp* ptrSendRtpRtcpModule = vieEncoder->SendRtpRtcpModule(); + if (vieChannel->RegisterSendRtpRtcpModule(*ptrSendRtpRtcpModule) != 0) + { + assert(false); + _vieEncoderMap.Erase(channelId); + _channelMap.Erase(channelId); + ReturnChannelId(channelId); + delete vieChannel; + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, channelId), + "%s: Could not register rtp module %d", __FUNCTION__, + channelId); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// CreateChannel +// +// Creates a channel and attaches to an already existing ViEEncoder +// ---------------------------------------------------------------------------- + +int ViEChannelManager::CreateChannel(int& channelId, int originalChannel) +{ + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + + // Check that originalChannel already exists + ViEEncoder* vieEncoder = ViEEncoderPtr(originalChannel); + if (vieEncoder == NULL) + { + // The original channel doesn't exist + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Original channel doesn't exist", __FUNCTION__, + originalChannel); + return -1; + } + // Get a free id for the new channel + if (GetFreeChannelId(channelId) == false) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "Max number of channels reached: %d", _channelMap.Size()); + return -1; + } + ViEChannel* vieChannel = new ViEChannel(channelId, _engineId, + _numberOfCores, + *_moduleProcessThread); + if (vieChannel == NULL) + { + ReturnChannelId(channelId); + return -1; + } + if (vieChannel->Init() != 0) + { + // Could not init channel + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s could not init channel", __FUNCTION__, channelId); + ReturnChannelId(channelId); + delete vieChannel; + vieChannel = NULL; + return -1; + } + if (_vieEncoderMap.Insert(channelId, vieEncoder) != 0) + { + // Could not add to the map + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could not add new encoder for video channel %d", + __FUNCTION__, channelId); + ReturnChannelId(channelId); + delete vieChannel; + return -1; + } + + // Set the same encoder settings for the channel as used by the master channel. + // Do this before attaching rtp module to ensure all rtp cihldren has the same codec type + VideoCodec encoder; + if (vieEncoder->GetEncoder(encoder) == 0) + { + vieChannel->SetSendCodec(encoder); + } + _channelMap.Insert(channelId, vieChannel); + + // Register the channel at the encoder + RtpRtcp* ptrSendRtpRtcpModule = vieEncoder->SendRtpRtcpModule(); + if (vieChannel->RegisterSendRtpRtcpModule(*ptrSendRtpRtcpModule) != 0) + { + assert(false); + _vieEncoderMap.Erase(channelId); + _channelMap.Erase(channelId); + ReturnChannelId(channelId); + delete vieChannel; + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, channelId), + "%s: Could not register rtp module %d", __FUNCTION__, + channelId); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DeleteChannel +// ---------------------------------------------------------------------------- + +int ViEChannelManager::DeleteChannel(int channelId) +{ + ViEChannel* vieChannel = NULL; + ViEEncoder* vieEncoder = NULL; + { + // Write lock to make sure no one is using the channel + ViEManagerWriteScoped wl(*this); + + // Protect the map + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + + MapItem* mapItem = _channelMap.Find(channelId); + if (mapItem == NULL) + { + // No such channel + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s Channel doesn't exist: %d", __FUNCTION__, channelId); + return -1; + } + vieChannel = reinterpret_cast (mapItem->GetItem()); + _channelMap.Erase(mapItem); + // Deregister the channel from the ViEEncoder to stop the media flow + vieChannel->DeregisterSendRtpRtcpModule(); + ReturnChannelId(channelId); + + // Find the encoder object + mapItem = _vieEncoderMap.Find(channelId); + if (mapItem == NULL) + { + assert(false); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s ViEEncoder not found for channel %d", __FUNCTION__, + channelId); + return -1; + } + // Get the ViEEncoder item + vieEncoder = reinterpret_cast (mapItem->GetItem()); + + // Check if other channels are using the same encoder + if (ChannelUsingViEEncoder(channelId)) + { + // Don't delete the ViEEncoder, at least on other channel is using it. + WEBRTC_TRACE( + webrtc::kTraceInfo, + webrtc::kTraceVideo, + ViEId(_engineId), + "%s ViEEncoder removed from map for channel %d, not deleted", + __FUNCTION__, channelId); + vieEncoder = NULL; + } else + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s ViEEncoder deleted for channel %d", __FUNCTION__, + channelId); + // Delete later when we've released the critsect + } + // We can't erase the item before we've checked for other channels using same ViEEncoder + _vieEncoderMap.Erase(mapItem); + + } + // Leave the write critsect before deleting the objects. + // Deleting a channel can cause other objects, such as renderers, to be deleted and might take time + if (vieEncoder) + { + delete vieEncoder; + } + delete vieChannel; + + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s Channel %d deleted", __FUNCTION__, channelId); + return 0; +} + +// ---------------------------------------------------------------------------- +// Channel +// +// Returns a pointer to the channel with id 'channelId' +// ---------------------------------------------------------------------------- + +ViEChannel* ViEChannelManager::ViEChannelPtr(int channelId) const +{ + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + MapItem* mapItem = _channelMap.Find(channelId); + if (mapItem == NULL) + { + // No such channel + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s Channel doesn't exist: %d", __FUNCTION__, channelId); + return NULL; + } + ViEChannel* vieChannel = reinterpret_cast (mapItem->GetItem()); + return vieChannel; +} + +// ---------------------------------------------------------------------------- +// GetChannels +// +// Adds all channels to channelMap +// ---------------------------------------------------------------------------- + +void ViEChannelManager::GetViEChannels(MapWrapper& channelMap) +{ + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + if (channelMap.Size() == 0) + { + // No channels + return; + } + // Add all items to 'channelMap' + for (MapItem* item = _channelMap.First(); item != NULL; item + = _channelMap.Next(item)) + { + channelMap.Insert(item->GetId(), item->GetItem()); + } + return; +} + +// ---------------------------------------------------------------------------- +// ViEEncoderPtr +// +// Gets the ViEEncoder used as input for videoChannelId +// ---------------------------------------------------------------------------- + +ViEEncoder* ViEChannelManager::ViEEncoderPtr(int videoChannelId) const +{ + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + MapItem* mapItem = _vieEncoderMap.Find(videoChannelId); + if (mapItem == NULL) + { + // No ViEEncoder for this channel... + return NULL; + } + ViEEncoder* vieEncoder = static_cast (mapItem->GetItem()); + return vieEncoder; +} + +// ---------------------------------------------------------------------------- +// GetFreeChannelId +// +// Returns true if we found a new channel id, freeChannelId, false otherwise +// ---------------------------------------------------------------------------- +bool ViEChannelManager::GetFreeChannelId(int& freeChannelId) +{ + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + int idx = 0; + while (idx < _freeChannelIdsSize) + { + if (_freeChannelIds[idx] == true) + { + // We've found a free id, allocate it and return + _freeChannelIds[idx] = false; + freeChannelId = idx + kViEChannelIdBase; + return true; + } + idx++; + } + // No free channel id + freeChannelId = -1; + return false; +} + +// ---------------------------------------------------------------------------- +// ReturnChannelID +// +// Returns a previously allocated channel id +// ---------------------------------------------------------------------------- +void ViEChannelManager::ReturnChannelId(int channelId) +{ + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + assert(channelId < kViEMaxNumberOfChannels+kViEChannelIdBase && channelId>=kViEChannelIdBase); + _freeChannelIds[channelId - kViEChannelIdBase] = true; +} + +// ---------------------------------------------------------------------------- +// ChannelUsingViEEncoder +// +// Returns true if at least one nother channel is using the same encoder +// ---------------------------------------------------------------------------- + +bool ViEChannelManager::ChannelUsingViEEncoder(int channelId) const +{ + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + MapItem* channelItem = _vieEncoderMap.Find(channelId); + if (channelItem == NULL) + { + // No ViEEncoder for this channel... + return false; + } + ViEEncoder* channelEncoder = + static_cast (channelItem->GetItem()); + + // Loop through all other channels to see if anyone points at the same ViEEncoder + MapItem* mapItem = _vieEncoderMap.First(); + while (mapItem) + { + ViEEncoder* vieEncoder = static_cast (mapItem->GetItem()); + if (mapItem->GetId() != channelId) + { + if (channelEncoder == static_cast (mapItem->GetItem())) + { + // We've found another channel using the same ViEEncoder + return true; + } + } + mapItem = _vieEncoderMap.Next(mapItem); + } + return false; +} + +// ---------------------------------------------------------------------------- +// SetVoiceEngine +// +// Set the voice engine instance to be used by all video channels. We are interested in the voice engine sync interfaces +// ---------------------------------------------------------------------------- +int ViEChannelManager::SetVoiceEngine(VoiceEngine* voiceEngine) +{ + + // Write lock to make sure no one is using the channel + ViEManagerWriteScoped wl(*this); + + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + + VoEVideoSync* syncInterface = NULL; + if (voiceEngine) + { + // Get new sync interface; + syncInterface = VoEVideoSync::GetInterface(voiceEngine); + if (!syncInterface) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s Can't get audio sync interface from VoiceEngine.", + __FUNCTION__); + + if (syncInterface) + { + syncInterface->Release(); + } + return -1; + } + } + + for (MapItem* item = _channelMap.First(); item != NULL; item + = _channelMap.Next(item)) + { + ViEChannel* channel = static_cast (item->GetItem()); + assert(channel); + channel->SetVoiceChannel(-1, syncInterface); + } + if (_voiceSyncInterface) + { + _voiceSyncInterface->Release(); + } + _voiceEngine = voiceEngine; + _voiceSyncInterface = syncInterface; + return 0; + +} +VoiceEngine* ViEChannelManager::GetVoiceEngine() +{ + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + return _voiceEngine; + +} + +// ---------------------------------------------------------------------------- +// ConnectVoiceChannel +// +// Enables lip sync of the channel. +// ---------------------------------------------------------------------------- +int ViEChannelManager::ConnectVoiceChannel(int channelId, int audioChannelId) +{ + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + + if (_voiceSyncInterface == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, channelId), + "No VoE set"); + return -1; + } + ViEChannel* channel = ViEChannelPtr(channelId); + if (!channel) + { + return -1; + } + return channel->SetVoiceChannel(audioChannelId, _voiceSyncInterface); + +} + +// ---------------------------------------------------------------------------- +// DisconnectVoiceChannel +// +// Disables lip sync of the channel. +// ---------------------------------------------------------------------------- +int ViEChannelManager::DisconnectVoiceChannel(int channelId) +{ + CriticalSectionScoped cs(*_ptrChannelIdCritsect); + ViEChannel* channel = ViEChannelPtr(channelId); + if (channel) + { + channel->SetVoiceChannel(-1, NULL); + return 0; + } else + { + return -1; + } +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_channel_manager.h b/video_engine/main/source/vie_channel_manager.h new file mode 100644 index 0000000000..2fb6c8499b --- /dev/null +++ b/video_engine/main/source/vie_channel_manager.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_channel_manager.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CHANNEL_MANAGER_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CHANNEL_MANAGER_H_ + +// Defines +#include "engine_configurations.h" +#include "vie_defines.h" +#include "typedefs.h" +#include "map_wrapper.h" +#include "vie_manager_base.h" + +namespace webrtc +{ +class CriticalSectionWrapper; +//class VoiceEngine; +class ProcessThread; +class ViEChannel; +class VoEVideoSync; +class ViEPerformanceMonitor; +class ViEEncoder; +class VoiceEngine; + +// ------------------------------------------------------------------ +// ViEChannelManager +// ------------------------------------------------------------------ + +class ViEChannelManager: private ViEManagerBase +{ + friend class ViEChannelManagerScoped; + +public: + ViEChannelManager(int engineId, int numberOfCores, + ViEPerformanceMonitor& viePerformanceMonitor); + ~ViEChannelManager(); + + void SetModuleProcessThread(ProcessThread& moduleProcessThread); + int CreateChannel(int& channelId); + int CreateChannel(int& channelId, int originalChannel); + int DeleteChannel(int channelId); + int SetVoiceEngine(VoiceEngine* voiceEngine); + int ConnectVoiceChannel(int channelId, int audioChannelId); + int DisconnectVoiceChannel(int channelId); + VoiceEngine* GetVoiceEngine(); + +private: + // Used by ViEChannelScoped, forcing a manager user to use scoped + ViEChannel* ViEChannelPtr(int channelId) const; + void GetViEChannels(MapWrapper& channelMap); + + // Methods used by ViECaptureScoped and ViEEncoderScoped + ViEEncoder* ViEEncoderPtr(int videoChannelId) const; + + bool GetFreeChannelId(int& freeChannelId); + void ReturnChannelId(int channelId); + + // Returns true if at least one other channels uses the same ViEEncoder as channelId + bool ChannelUsingViEEncoder(int channelId) const; + + // Members + CriticalSectionWrapper* _ptrChannelIdCritsect; // protecting _channelMap and _freeChannelIds + int _engineId; + int _numberOfCores; + ViEPerformanceMonitor& _viePerformanceMonitor; + MapWrapper _channelMap; + bool* _freeChannelIds; + int _freeChannelIdsSize; + // Encoder + MapWrapper _vieEncoderMap; // Channel id -> ViEEncoder + VoEVideoSync* _voiceSyncInterface; + VoiceEngine* _voiceEngine; + ProcessThread* _moduleProcessThread; +}; + +// ------------------------------------------------------------------ +// ViEChannelManagerScoped +// ------------------------------------------------------------------ +class ViEChannelManagerScoped: private ViEManagerScopedBase +{ +public: + ViEChannelManagerScoped(const ViEChannelManager& vieChannelManager); + ViEChannel* Channel(int vieChannelId) const; + ViEEncoder* Encoder(int vieChannelId) const; + + // Returns true if at lease one other channels uses the same ViEEncoder as channelId + bool ChannelUsingViEEncoder(int channelId) const; +}; + +} //namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CHANNEL_MANAGER_H_ diff --git a/video_engine/main/source/vie_codec_impl.cc b/video_engine/main/source/vie_codec_impl.cc new file mode 100644 index 0000000000..a2f3aa9fac --- /dev/null +++ b/video_engine/main/source/vie_codec_impl.cc @@ -0,0 +1,977 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_codec_impl.cc + */ + +#include "vie_codec_impl.h" + +// Defines +#include "engine_configurations.h" +#include "vie_defines.h" + +#include "video_coding.h" +#include "trace.h" +#include "vie_errors.h" +#include "vie_impl.h" +#include "vie_channel.h" +#include "vie_channel_manager.h" +#include "vie_encoder.h" +#include "vie_input_manager.h" +#include "vie_capturer.h" + +#include + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// GetInterface +// ---------------------------------------------------------------------------- + +ViECodec* ViECodec::GetInterface(VideoEngine* videoEngine) +{ +#ifdef WEBRTC_VIDEO_ENGINE_CODEC_API + if (videoEngine == NULL) + { + return NULL; + } + VideoEngineImpl* vieImpl = reinterpret_cast (videoEngine); + ViECodecImpl* vieCodecImpl = vieImpl; + (*vieCodecImpl)++; // Increase ref count + + return vieCodecImpl; +#else + return NULL; +#endif +} + +// ---------------------------------------------------------------------------- +// Release +// +// Releases the interface, i.e. reduces the reference counter. The number of +// remaining references is returned, -1 if released too many times. +// ---------------------------------------------------------------------------- + +int ViECodecImpl::Release() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "ViECodecImpl::Release()"); + (*this)--; // Decrease ref count + + WebRtc_Word32 refCount = GetCount(); + if (refCount < 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, + "ViECodec released too many times"); + SetLastError(kViEAPIDoesNotExist); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId, + "ViECodec reference count: %d", refCount); + return refCount; +} + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViECodecImpl::ViECodecImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViECodecImpl::ViECodecImpl() Ctor"); +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViECodecImpl::~ViECodecImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViECodecImpl::~ViECodecImpl() Dtor"); +} + +// Available codecs +// ---------------------------------------------------------------------------- +// NumberOfCodecs +// +// Returns the number of available codecs +// ---------------------------------------------------------------------------- + +int ViECodecImpl::NumberOfCodecs() const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + // +2 because of FEC(RED and ULPFEC) + return (int) (VideoCodingModule::NumberOfCodecs() + 2); +} + +// ---------------------------------------------------------------------------- +// GetCodec +// +// Return the video codec with listNumber +// ---------------------------------------------------------------------------- + +int ViECodecImpl::GetCodec(const unsigned char listNumber, + VideoCodec& videoCodec) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(listNumber: %d, codecType: %d)", __FUNCTION__, listNumber); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + if (listNumber == VideoCodingModule::NumberOfCodecs()) + { + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + strcpy(videoCodec.plName, "RED"); + videoCodec.codecType = kVideoCodecRED; + videoCodec.plType = VCM_RED_PAYLOAD_TYPE; + } + else if (listNumber == VideoCodingModule::NumberOfCodecs() + 1) + { + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + strcpy(videoCodec.plName, "ULPFEC"); + videoCodec.codecType = kVideoCodecULPFEC; + videoCodec.plType = VCM_ULPFEC_PAYLOAD_TYPE; + } + else if (VideoCodingModule::Codec(listNumber, &videoCodec) + != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Could not get codec for listNumber: %u", __FUNCTION__, + listNumber); + SetLastError(kViECodecInvalidArgument); + return -1; + } + return 0; +} + +// Codec settings +// ---------------------------------------------------------------------------- +// SetSendCodec +// +// Sets the send codec for videoChannel +// This call will affect all channels using the same encoder +// ---------------------------------------------------------------------------- + +int ViECodecImpl::SetSendCodec(const int videoChannel, + const VideoCodec& videoCodec) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId,videoChannel), + "%s(videoChannel: %d, codecType: %d)", __FUNCTION__, + videoChannel, videoCodec.codecType); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_instanceId, videoChannel), + "%s: codec: %d, plType: %d, width: %d, height: %d, bitrate: %d" + "maxBr: %d, minBr: %d, frameRate: %d)", __FUNCTION__, + videoCodec.codecType, videoCodec.plType, videoCodec.width, + videoCodec.height, videoCodec.startBitrate, + videoCodec.maxBitrate, videoCodec.minBitrate, + videoCodec.maxFramerate); + + if (CodecValid(videoCodec) == false) + { + // Error logged + SetLastError(kViECodecInvalidCodec); + return -1; + } + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + + // Set a maxBitrate if the user hasn't... + VideoCodec videoCodecInternal; + memcpy(&videoCodecInternal, &videoCodec, sizeof(webrtc::VideoCodec)); + if (videoCodecInternal.maxBitrate == 0) + { + // Max is one bit per pixel ... + videoCodecInternal.maxBitrate = (videoCodecInternal.width + * videoCodecInternal.height * videoCodecInternal.maxFramerate) + / 1000; + if (videoCodecInternal.startBitrate > videoCodecInternal.maxBitrate) + { + // ... but should'nt limit the set start bitrate. + videoCodecInternal.maxBitrate = videoCodecInternal.startBitrate; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_instanceId, + videoChannel), + "%s: New max bitrate set to %d kbps", __FUNCTION__, + videoCodecInternal.maxBitrate); + } + + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (vieEncoder == NULL) + { + assert(false); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: No encoder found for channel %d", __FUNCTION__); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + + // We need to check if the codec settings changed, + // then we need a new SSRC + bool newRtpStream = false; + + VideoCodec encoder; + vieEncoder->GetEncoder(encoder); + if (encoder.codecType != videoCodecInternal.codecType || + encoder.width != videoCodecInternal.width || + encoder.height != videoCodecInternal.height) + { + if (cs.ChannelUsingViEEncoder(videoChannel)) + { + // We don't allow changing codec type or size when several + // channels share encoder. + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Settings differs from other channels using encoder", + __FUNCTION__); + SetLastError(kViECodecInUse); + return -1; + } + newRtpStream = true; + } + + ViEInputManagerScoped is(_inputManager); + ViEFrameProviderBase* frameProvider = NULL; + + // Stop the media flow while reconfiguring + vieEncoder->Pause(); + + // Check if we have a frame provider that is a camera and can provide this + // codec for us. + bool useCaptureDeviceAsEncoder = false; + frameProvider = is.FrameProvider(vieEncoder); + if (frameProvider) + { + ViECapturer* vieCapture = static_cast (frameProvider); + // Try to get preencoded. Nothing to do if it is not supported. + if (vieCapture && vieCapture->PreEncodeToViEEncoder(videoCodecInternal, + *vieEncoder, + videoChannel) == 0) + { + useCaptureDeviceAsEncoder = true; + } + } + + // Update the encoder settings if we are not using a capture device capable + // of this codec. + if (!useCaptureDeviceAsEncoder + && vieEncoder->SetEncoder(videoCodecInternal) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Could not change encoder for channel %d", __FUNCTION__, + videoChannel); + SetLastError(kViECodecUnknownError); + return -1; + } + + // Give the channel the new information + if (vieChannel->SetSendCodec(videoCodecInternal, newRtpStream) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Could not set send codec for channel %d", __FUNCTION__, + videoChannel); + SetLastError(kViECodecUnknownError); + return -1; + } + + // Update the protection mode, we might be switching NACK/FEC + vieEncoder->UpdateProtectionMethod(); + // Get new best format for frame provider + if (frameProvider) + { + frameProvider->FrameCallbackChanged(); + } + // Restart the media flow + if (newRtpStream) + { + // Stream settings changed, make sure we get a key frame + vieEncoder->SendKeyFrame(); + } + vieEncoder->Restart(); + + return 0; +} + +// ---------------------------------------------------------------------------- +// GetSendCodec +// +// Gets the current send codec +// ---------------------------------------------------------------------------- + +int ViECodecImpl::GetSendCodec(const int videoChannel, + VideoCodec& videoCodec) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (vieEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: No encoder for channel %d", __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + + return vieEncoder->GetEncoder(videoCodec); +} + +// ---------------------------------------------------------------------------- +// SetReceiveCodec +// +// Registers a possible receive codec +// ---------------------------------------------------------------------------- + +int ViECodecImpl::SetReceiveCodec(const int videoChannel, + const VideoCodec& videoCodec) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d, codecType: %d)", __FUNCTION__, + videoChannel, videoCodec.codecType); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_instanceId, videoChannel), + "%s: codec: %d, plType: %d, width: %d, height: %d, bitrate: %d," + "maxBr: %d, minBr: %d, frameRate: %d", __FUNCTION__, + videoCodec.codecType, videoCodec.plType, videoCodec.width, + videoCodec.height, videoCodec.startBitrate, + videoCodec.maxBitrate, videoCodec.minBitrate, + videoCodec.maxFramerate); + + if (CodecValid(videoCodec) == false) + { + // Error logged + SetLastError(kViECodecInvalidCodec); + return -1; + } + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + + if (vieChannel->SetReceiveCodec(videoCodec) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId, + videoChannel), + "%s: Could not set receive codec for channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecUnknownError); + return -1; + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// GetReceiveCodec +// +// Gets the current receive codec +// ---------------------------------------------------------------------------- + +int ViECodecImpl::GetReceiveCodec(const int videoChannel, + VideoCodec& videoCodec) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d, codecType: %d)", __FUNCTION__, + videoChannel, videoCodec.codecType); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + + if (vieChannel->GetReceiveCodec(videoCodec) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetCodecConfigParameters +// +// Gets the codec config parameters to be sent out-of-band. +// ---------------------------------------------------------------------------- + +int ViECodecImpl::GetCodecConfigParameters( + const int videoChannel, + unsigned char configParameters[kConfigParameterSize], + unsigned char& configParametersSize) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (vieEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: No encoder for channel %d", __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + + if (vieEncoder->GetCodecConfigParameters(configParameters, + configParametersSize) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// SetImageScaleStatus +// +// Enables scaling of the encoded image instead of padding black border or +// cropping +// ---------------------------------------------------------------------------- + +int ViECodecImpl::SetImageScaleStatus(const int videoChannel, const bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d, enable: %d)", __FUNCTION__, videoChannel, + enable); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (vieEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + + if (vieEncoder->ScaleInputImage(enable) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; +} + +// Codec statistics +// ---------------------------------------------------------------------------- +// GetSendCodecStastistics +// +// Get codec statistics for outgoing stream +// ---------------------------------------------------------------------------- + + +int ViECodecImpl::GetSendCodecStastistics(const int videoChannel, + unsigned int& keyFrames, + unsigned int& deltaFrames) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(videoChannel %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (vieEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: No send codec for channel %d", __FUNCTION__, + videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + + if (vieEncoder->SendCodecStatistics((WebRtc_UWord32&) keyFrames, + (WebRtc_UWord32&) deltaFrames) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetReceiveCodecStastistics +// +// Get codec statistics for incoming stream +// ---------------------------------------------------------------------------- + +int ViECodecImpl::GetReceiveCodecStastistics(const int videoChannel, + unsigned int& keyFrames, + unsigned int& deltaFrames) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d, codecType: %d)", __FUNCTION__, + videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + if (vieChannel->ReceiveCodecStatistics((WebRtc_UWord32&) keyFrames, + (WebRtc_UWord32&) deltaFrames) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; + +} + +// Callbacks +// ---------------------------------------------------------------------------- +// SetKeyFrameRequestCallbackStatus +// +// Enables a kecallback for keyframe request instead of using RTCP +// ---------------------------------------------------------------------------- + +int ViECodecImpl::SetKeyFrameRequestCallbackStatus(const int videoChannel, + const bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + if (vieChannel->EnableKeyFrameRequestCallback(enable) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; + +} + +// ---------------------------------------------------------------------------- +// SetSignalKeyPacketLossStatus +// +// Triggers a key frame request when there is packet loss in a received key +// frame +// ---------------------------------------------------------------------------- + +int ViECodecImpl::SetSignalKeyPacketLossStatus(const int videoChannel, + const bool enable, + const bool onlyKeyFrames) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d, enable: %d, onlyKeyFrames: %d)", + __FUNCTION__, videoChannel, enable); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + if (vieChannel->SetSignalPacketLossStatus(enable, onlyKeyFrames) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterEncoderObserver +// ---------------------------------------------------------------------------- + +int ViECodecImpl::RegisterEncoderObserver(const int videoChannel, + ViEEncoderObserver& observer) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (vieEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: No encoder for channel %d", __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + if (vieEncoder->RegisterCodecObserver(&observer) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Could not register codec observer at channel", + __FUNCTION__); + SetLastError(kViECodecObserverAlreadyRegistered); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterEncoderObserver +// ---------------------------------------------------------------------------- + +int ViECodecImpl::DeregisterEncoderObserver(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (vieEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: No encoder for channel %d", __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + if (vieEncoder->RegisterCodecObserver(NULL) != 0) + { + SetLastError(kViECodecObserverNotRegistered); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterDecoderObserver +// ---------------------------------------------------------------------------- + +int ViECodecImpl::RegisterDecoderObserver(const int videoChannel, + ViEDecoderObserver& observer) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + if (vieChannel->RegisterCodecObserver(&observer) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Could not register codec observer at channel", + __FUNCTION__); + SetLastError(kViECodecObserverAlreadyRegistered); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterDecoderObserver +// ---------------------------------------------------------------------------- + +int ViECodecImpl::DeregisterDecoderObserver(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + if (vieChannel->RegisterCodecObserver(NULL) != 0) + { + SetLastError(kViECodecObserverNotRegistered); + return -1; + } + + return 0; +} + +// Force a key frame +// ---------------------------------------------------------------------------- +// SendKeyFrame +// +// Force the next frame to be a key frame +// ---------------------------------------------------------------------------- + +int ViECodecImpl::SendKeyFrame(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(videoChannel: %d)", __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (vieEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + if (vieEncoder->SendKeyFrame() != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; + +} + +// ---------------------------------------------------------------------------- +// WaitForFirstKeyFrame +// +// Forc the next frame to be a key frame +// ---------------------------------------------------------------------------- + +int ViECodecImpl::WaitForFirstKeyFrame(const int videoChannel, const bool wait) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(videoChannel: %d, wait: %d)", __FUNCTION__, videoChannel, + wait); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + if (vieChannel->WaitForKeyFrame(wait) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; +} + +// H263 Specific +// ---------------------------------------------------------------------------- +// SetInverseH263Logic +// +// Used to interoperate with old MS H.263 where key frames are marked as delta +// and the oposite. +// ---------------------------------------------------------------------------- + +int ViECodecImpl::SetInverseH263Logic(int videoChannel, bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(videoChannel: %d)", __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId,videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidChannelId); + return -1; + } + if (vieChannel->SetInverseH263Logic(enable) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// CodecValid +// ---------------------------------------------------------------------------- + +bool ViECodecImpl::CodecValid(const VideoCodec& videoCodec) +{ + // Check plName matches codecType + if (videoCodec.codecType == kVideoCodecRED) + { +#if defined(WIN32) + if (_strnicmp(videoCodec.plName, "red", 3) == 0) +#elif defined(WEBRTC_MAC_INTEL) || defined(WEBRTC_LINUX) + if (strncasecmp(videoCodec.plName, "red",3) == 0) +#endif + { + // We only care about the type and name for red + return true; + } + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, + "Codec type doesn't match plName", videoCodec.plType); + return false; + } + else if (videoCodec.codecType == kVideoCodecULPFEC) + { +#if defined(WIN32) + if (_strnicmp(videoCodec.plName, "ULPFEC", 6) == 0) +#elif defined(WEBRTC_MAC_INTEL)|| defined(WEBRTC_LINUX) + if (strncasecmp(videoCodec.plName, "ULPFEC",6) == 0) +#endif + { + // We only care about the type and name for ULPFEC + return true; + } + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, + "Codec type doesn't match plName", videoCodec.plType); + return false; + } + else if ((videoCodec.codecType == kVideoCodecH263 && + strncmp(videoCodec.plName, "H263", 4) == 0) + || (videoCodec.codecType == kVideoCodecH263 + && strncmp(videoCodec.plName, "H263-1998", 9) == 0) + || (videoCodec.codecType == kVideoCodecVP8 + && strncmp(videoCodec.plName, "VP8", 4) == 0) + || (videoCodec.codecType == kVideoCodecI420 + && strncmp(videoCodec.plName, "I420", 4) == 0) + || (videoCodec.codecType == kVideoCodecH264 + && strncmp(videoCodec.plName, "H264", 4) == 0)) + // || (videoCodec.codecType == kVideoCodecMPEG4 + // && strncmp(videoCodec.plName, "MP4V-ES", 7) == 0) + { + // ok + } + else + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, + "Codec type doesn't match plName", videoCodec.plType); + return false; + } + + // pltype + if (videoCodec.plType == 0 && videoCodec.plType > 127) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, + "Invalid codec payload type: %d", videoCodec.plType); + return false; + } + + // Size + if (videoCodec.width > kViEMaxCodecWidth || videoCodec.height + > kViEMaxCodecHeight) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, + "Invalid codec size: %u x %u", videoCodec.width, + videoCodec.height); + return false; + } + + if (videoCodec.startBitrate < kViEMinCodecBitrate) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, + "Invalid startBitrate: %u", videoCodec.startBitrate); + return false; + } + if (videoCodec.minBitrate < kViEMinCodecBitrate) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, + "Invalid minBitrate: %u", videoCodec.minBitrate); + return false; + } + if (videoCodec.startBitrate < kViEMinCodecBitrate) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, + "Invalid minBitrate: %u", videoCodec.minBitrate); + return false; + } + + if (videoCodec.codecType == kVideoCodecH263) + { + if ((videoCodec.width == 704 && videoCodec.height == 576) + || (videoCodec.width == 352 && videoCodec.height == 288) + || (videoCodec.width == 176 && videoCodec.height == 144) + || (videoCodec.width == 128 && videoCodec.height == 96)) + { + // ok + } + else + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, + "Invalid size for H.263"); + return false; + } + } + return true; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_codec_impl.h b/video_engine/main/source/vie_codec_impl.h new file mode 100644 index 0000000000..b47c7a2281 --- /dev/null +++ b/video_engine/main/source/vie_codec_impl.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_codec_impl.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CODEC_IMPL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CODEC_IMPL_H_ + +#include "vie_defines.h" + +#include "typedefs.h" +#include "vie_ref_count.h" +#include "vie_shared_data.h" +#include "vie_codec.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// ViECodecImpl +// ---------------------------------------------------------------------------- + +class ViECodecImpl : public virtual ViESharedData, + public ViECodec, + public ViERefCount +{ +public: + virtual int Release(); + + // Available codecs + virtual int NumberOfCodecs() const; + + virtual int GetCodec(const unsigned char listNumber, + VideoCodec& videoCodec) const; + + // Codec settings + virtual int SetSendCodec(const int videoChannel, + const VideoCodec& videoCodec); + + virtual int GetSendCodec(const int videoChannel, + VideoCodec& videoCodec) const; + + virtual int SetReceiveCodec(const int videoChannel, + const VideoCodec& videoCodec); + + virtual int GetReceiveCodec(const int videoChannel, + VideoCodec& videoCodec) const; + + virtual int GetCodecConfigParameters( + const int videoChannel, + unsigned char configParameters[kConfigParameterSize], + unsigned char& configParametersSize) const; + + // Input image scaling + virtual int SetImageScaleStatus(const int videoChannel, const bool enable); + + // Codec statistics + virtual int GetSendCodecStastistics(const int videoChannel, + unsigned int& keyFrames, + unsigned int& deltaFrames) const; + + virtual int GetReceiveCodecStastistics(const int videoChannel, + unsigned int& keyFrames, + unsigned int& deltaFrames) const; + + // Callbacks + virtual int SetKeyFrameRequestCallbackStatus(const int videoChannel, + const bool enable); + + virtual int SetSignalKeyPacketLossStatus(const int videoChannel, + const bool enable, + const bool onlyKeyFrames = false); + + virtual int RegisterEncoderObserver(const int videoChannel, + ViEEncoderObserver& observer); + + virtual int DeregisterEncoderObserver(const int videoChannel); + + virtual int RegisterDecoderObserver(const int videoChannel, + ViEDecoderObserver& observer); + + virtual int DeregisterDecoderObserver(const int videoChannel); + + // Key frame settings + virtual int SendKeyFrame(const int videoChannel); + + virtual int WaitForFirstKeyFrame(const int videoChannel, const bool wait); + + // H263 Specific + virtual int SetInverseH263Logic(int videoChannel, bool enable); + +protected: + ViECodecImpl(); + virtual ~ViECodecImpl(); + +private: + bool CodecValid(const VideoCodec& videoCodec); +}; +} // namespace webrtc + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_CODEC_IMPL_H_ diff --git a/video_engine/main/source/vie_defines.h b/video_engine/main/source/vie_defines.h new file mode 100644 index 0000000000..42f720b5c5 --- /dev/null +++ b/video_engine/main/source/vie_defines.h @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_defines.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_DEFINES_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_DEFINES_H_ + +#include "engine_configurations.h" + +#ifdef WEBRTC_MAC_INTEL +#include +#include +#endif + +#ifdef ANDROID +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +namespace webrtc +{ +// =================================================== +// ViE Defines +// =================================================== + +// General +enum { kViEMinKeyRequestIntervalMs = 300}; + +// ViEBase +enum { kViEMaxNumberOfChannels = 4}; +enum { kViEVersionMaxMessageSize = 1024 }; +enum { kViEMaxModuleVersionSize = 960 }; + +// ViECapture +enum { kViEMaxCaptureDevices=10}; +// Width used if no send codec has been set when a capture device is started +enum { kViECaptureDefaultWidth = 352}; +// Height used if no send codec has been set when a capture device is started +enum { kViECaptureDefaultHeight = 288}; +enum { kViECaptureDefaultFramerate = 30}; +enum { kViECaptureMaxSnapshotWaitTimeMs = 500 }; + +// ViECodec +enum { kViEMaxCodecWidth = 1920}; +enum { kViEMaxCodecHeight = 1200}; +enum { kViEMaxCodecFramerate = 60}; +enum { kViEMinCodecBitrate = 30}; + +// ViEEncryption +enum { kViEMaxSrtpKeyLength = 30}; +enum { kViEMinSrtpEncryptLength = 16}; +enum { kViEMaxSrtpEncryptLength = 256}; +enum { kViEMaxSrtpAuthSh1Length = 20}; +enum { kViEMaxSrtpTagAuthNullLength = 12}; +enum { kViEMaxSrtpKeyAuthNullLength = 256}; + +// ViEExternalCodec + +// ViEFile +enum { kViEMaxFilePlayers = 3}; + +// ViEImageProcess + +// ViENetwork +enum { kViEMaxMtu = 1500}; +enum { kViESocketThreads = 1}; +enum { kViENumReceiveSocketBuffers = 500}; + +// ViERender +// Max valid time set in SetRenderTimeoutImage +enum { kViEMaxRenderTimeoutTimeMs = 10000}; +// Min valid time set in SetRenderTimeoutImage +enum { kViEMinRenderTimeoutTimeMs = 33}; +enum { kViEDefaultRenderDelayMs = 10}; + +// ViERTP_RTCP +enum { kNackHistorySize = 400}; + +// Id definitions +enum { + kViEChannelIdBase=0x0, + kViEChannelIdMax=0xFF, + kViECaptureIdBase=0x1001, + kViECaptureIdMax=0x10FF, + kViEFileIdBase=0x2000, + kViEFileIdMax=0x200F, + kViEDummyChannelId=0xFFFF +}; + +// Module id +// Create a unique id based on the ViE instance id and the +// channel id. ViE id > 0 and 0 <= channel id <= 255 + +inline int ViEId(const int vieId, const int channelId = -1) +{ + if (channelId == -1) + { + return (int) ((vieId << 16) + kViEDummyChannelId); + } + return (int) ((vieId << 16) + channelId); +} + +inline int ViEModuleId(const int vieId, const int channelId = -1) +{ + if (channelId == -1) + { + return (int) ((vieId << 16) + kViEDummyChannelId); + } + return (int) ((vieId << 16) + channelId); +} + +inline int ChannelId(const int moduleId) +{ + return (int) (moduleId & 0xffff); +} + + +// ============================================================================ +// Platform specifics +// ============================================================================ + +//------------------------------------- +// Windows +//------------------------------------- + +#if defined(_WIN32) +// Build information macros + #if defined(_DEBUG) + #define BUILDMODE TEXT("d") + #elif defined(DEBUG) + #define BUILDMODE TEXT("d") + #elif defined(NDEBUG) + #define BUILDMODE TEXT("r") + #else + #define BUILDMODE TEXT("?") + #endif + + #define BUILDTIME TEXT(__TIME__) + #define BUILDDATE TEXT(__DATE__) + + // example: "Oct 10 2002 12:05:30 r" + #define BUILDINFO BUILDDATE TEXT(" ") BUILDTIME TEXT(" ") BUILDMODE + + + #define RENDER_MODULE_TYPE kRenderWindows + // Warning pragmas + #pragma warning(disable: 4351) // new behavior: elements of array 'XXX' will be default initialized + #pragma warning(disable: 4355) // 'this' : used in base member initializer list + #pragma warning(disable: 4731) // frame pointer register 'ebp' modified by inline assembly code + + // Include libraries + #pragma comment( lib, "winmm.lib" ) +#ifndef WEBRTC_EXTERNAL_TRANSPORT + #pragma comment( lib, "ws2_32.lib" ) + #pragma comment( lib, "Iphlpapi.lib" ) // _GetAdaptersAddresses +#endif +#endif + + +//------------------------------------- +// Mac +//------------------------------------- + +#ifdef WEBRTC_MAC_INTEL + #define SLEEP(x) usleep(x * 1000) + + // Build information macros + #define TEXT(x) x + #if defined(_DEBUG) + #define BUILDM//#define webrtc::kFileFormatAviFile 3 +//#define __LINUX__ // needed for InterObjects +ODE TEXT("d") + #elif defined(DEBUG) + #define BUILDMODE TEXT("d") + #elif defined(NDEBUG) + #define BUILDMODE TEXT("r") + #else + #define BUILDMODE TEXT("?") + #endif + + #define BUILDTIME TEXT(__TIME__) + #define BUILDDATE TEXT(__DATE__) + + // example: "Oct 10 2002 12:05:30 r" + #define BUILDINFO BUILDDATE TEXT(" ") BUILDTIME TEXT(" ") BUILDMODE + + #define RENDER_MODULE_TYPE kRenderWindows +#endif + +//#define webrtc::kFileFormatAviFile 3 +//#define __LINUX__ // needed for InterObjects + +//------------------------------------- +// Linux +//------------------------------------- + +#ifndef ANDROID +#ifdef WEBRTC_LINUX + +// Build information macros +#if defined(_DEBUG) + #define BUILDMODE "d" +#elif defined(DEBUG) + #define BUILDMODE "d" +#elif defined(NDEBUG) + #define BUILDMODE "r" +#else + #define BUILDMODE "?" +#endif + +#define BUILDTIME __TIME__ +#define BUILDDATE __DATE__ + +// example: "Oct 10 2002 12:05:30 r" +#define BUILDINFO BUILDDATE " " BUILDTIME " " BUILDMODE + +#endif // ifdef WEBRTC_LINUX +#endif // ifndef ANDROID + +#ifdef ANDROID + + #define DWORD unsigned long int + #define FALSE 0 + #define TRUE 1 + #define LONG int + #define LONGLONG long long + #define FAR + #define __cdecl + + #if defined(_DEBUG) + #define BUILDMODE "d" + #elif defined(DEBUG) + #define BUILDMODE "d" + #elif defined(NDEBUG) + #define BUILDMODE "r" + #else + #define BUILDMODE "?" + #endif + + #define BUILDTIME __TIME__ + #define BUILDDATE __DATE__ + + // example: "Oct 10 2002 12:05:30 r" + #define BUILDINFO BUILDDATE " " BUILDTIME " " BUILDMODE + + namespace + { + void Sleep(unsigned long x) + { + timespec t; + t.tv_sec = x/1000; + t.tv_nsec = (x-(x/1000)*1000)*1000000; + nanosleep(&t,NULL); + } + + DWORD timeGetTime() + { + struct timeval tv; + struct timezone tz; + unsigned long val; + + gettimeofday(&tv, &tz); + val= tv.tv_sec*1000+ tv.tv_usec/1000; + return(val); + } + } + + #define SLEEP(x) ::Sleep(x) + #define GET_TIME_IN_MS timeGetTime + +#endif // #ifdef ANDROID + +} //namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_DEFINES_H_ + diff --git a/video_engine/main/source/vie_encoder.cc b/video_engine/main/source/vie_encoder.cc new file mode 100644 index 0000000000..82c3889ee4 --- /dev/null +++ b/video_engine/main/source/vie_encoder.cc @@ -0,0 +1,1017 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * ViEEncoder.cpp + */ + +#include "vie_encoder.h" +#include "vie_defines.h" + +#include "critical_section_wrapper.h" +#include "process_thread.h" +#include "rtp_rtcp.h" +#include "video_coding.h" +#include "video_coding_defines.h" +#include "video_codec_interface.h" +#include "vie_codec.h" +#include "vie_image_process.h" +#include "tick_util.h" +#include "trace.h" + +#include +namespace webrtc { + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViEEncoder::ViEEncoder(WebRtc_Word32 engineId, WebRtc_Word32 channelId, + WebRtc_UWord32 numberOfCores, + ProcessThread& moduleProcessThread) + : + _engineId(engineId), + _channelId(channelId), + _numberOfCores(numberOfCores), + _vcm(*webrtc::VideoCodingModule::Create(ViEModuleId(engineId, channelId))), + _vpm(*webrtc::VideoProcessingModule::Create(ViEModuleId(engineId, channelId))), + _rtpRtcp(*RtpRtcp::CreateRtpRtcp(ViEModuleId(engineId, + channelId), + false)), + _callbackCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _dataCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _paused(false), _timeLastIntraRequestMs(0), + _channelsDroppingDeltaFrames(0), _dropNextFrame(false), + _fecEnabled(false), _codecObserver(NULL), _effectFilter(NULL), + _moduleProcessThread(moduleProcessThread), _hasReceivedSLI(false), + _pictureIdSLI(0), _hasReceivedRPSI(false), _pictureIdRPSI(0), + _fileRecorder(channelId) +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(engineId, channelId), + "%s(engineId: %d) 0x%p - Constructor", __FUNCTION__, engineId, + this); + + _vcm.InitializeSender(); + _vpm.EnableTemporalDecimation(true); + + // Enable/disable content analysis: off by default for now + _vpm.EnableContentAnalysis(false); + + _moduleProcessThread.RegisterModule(&_vcm); + _rtpRtcp.InitSender(); + _rtpRtcp.RegisterIncomingVideoCallback(this); + _rtpRtcp.RegisterIncomingRTCPCallback(this); + _moduleProcessThread.RegisterModule(&_rtpRtcp); + + // + _qmCallback = new QMTestVideoSettingsCallback(); + _qmCallback->RegisterVPM(&_vpm); + _qmCallback->RegisterVCM(&_vcm); + _qmCallback->SetNumOfCores(_numberOfCores); + +#ifdef VIDEOCODEC_VP8 + VideoCodec videoCodec; + if (_vcm.Codec(webrtc::kVideoCodecVP8, &videoCodec) == VCM_OK) + { + _vcm.RegisterSendCodec(&videoCodec, _numberOfCores, _rtpRtcp.MaxDataPayloadLength()); + _rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType); + } + else + { + assert(false); + } +#else + VideoCodec videoCodec; + if (_vcm.Codec(webrtc::kVideoCodecI420, &videoCodec) == VCM_OK) + { + _vcm.RegisterSendCodec(&videoCodec, _numberOfCores, _rtpRtcp.MaxDataPayloadLength()); + _rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType); + } + else + { + assert(false); + } +#endif + + if (_vcm.RegisterTransportCallback(this) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: VCM::RegisterTransportCallback failure"); + } + if (_vcm.RegisterSendStatisticsCallback(this) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: VCM::RegisterSendStatisticsCallback failure"); + } + + if (_vcm.RegisterVideoQMCallback(_qmCallback) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "VCM::RegisterQMCallback failure"); + } +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViEEncoder::~ViEEncoder() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "ViEEncoder Destructor 0x%p, engineId: %d", this, _engineId); + + if (_rtpRtcp.NumberChildModules() > 0) + { + assert(false); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Channels still attached %d, leaking memory", + _rtpRtcp.NumberChildModules()); + return; + } + _moduleProcessThread.DeRegisterModule(&_vcm); + _moduleProcessThread.DeRegisterModule(&_vpm); + _moduleProcessThread.DeRegisterModule(&_rtpRtcp); + delete &_vcm; + delete &_vpm; + delete &_rtpRtcp; + delete &_callbackCritsect; + delete &_dataCritsect; +} + +// ============================================================================ +// Start/Stop +// ============================================================================ + +// ---------------------------------------------------------------------------- +// Pause / Retart +// +// Call this to start/stop sending +// ---------------------------------------------------------------------------- + +void ViEEncoder::Pause() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + CriticalSectionScoped cs(_dataCritsect); + _paused = true; +} + +void ViEEncoder::Restart() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + CriticalSectionScoped cs(_dataCritsect); + _paused = false; +} + +// ---------------------------------------------------------------------------- +// DropDeltaAfterKey +// +// Drops the first delta frame after a key frame is encoded. +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::DropDeltaAfterKey(bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(%d)", __FUNCTION__, enable); + CriticalSectionScoped cs(_dataCritsect); + + if (enable) + { + _channelsDroppingDeltaFrames++; + } else + { + _channelsDroppingDeltaFrames--; + if (_channelsDroppingDeltaFrames < 0) + { + _channelsDroppingDeltaFrames = 0; + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: Called too many times", __FUNCTION__, enable); + return -1; + } + } + return 0; +} + +// ============================================================================ +// Codec settigns +// ============================================================================ + +// ---------------------------------------------------------------------------- +// NumberOfCodecs +// ---------------------------------------------------------------------------- + +WebRtc_UWord8 ViEEncoder::NumberOfCodecs() +{ + return _vcm.NumberOfCodecs(); +} + +// ---------------------------------------------------------------------------- +// GetCodec +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::GetCodec(WebRtc_UWord8 listIndex, + webrtc::VideoCodec& videoCodec) +{ + if (_vcm.Codec(listIndex, &videoCodec) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Could not get codec", + __FUNCTION__); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// External encoder +// ---------------------------------------------------------------------------- +WebRtc_Word32 ViEEncoder::RegisterExternalEncoder( + webrtc::VideoEncoder* encoder, + WebRtc_UWord8 plType) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: pltype %u", __FUNCTION__, plType); + + if (encoder == NULL) + return -1; + + if (_vcm.RegisterExternalEncoder(encoder, plType) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Could not register external encoder"); + return -1; + } + return 0; +} + +WebRtc_Word32 ViEEncoder::DeRegisterExternalEncoder(WebRtc_UWord8 plType) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: pltype %u", __FUNCTION__, plType); + + webrtc::VideoCodec currentSendCodec; + if (_vcm.SendCodec(¤tSendCodec) == VCM_OK) + { + currentSendCodec.startBitrate = _vcm.Bitrate(); + } + + if (_vcm.RegisterExternalEncoder(NULL, plType) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Could not deregister external encoder"); + return -1; + } + + // If the external encoder is the current send codec use vcm internal encoder + if (currentSendCodec.plType == plType) + { + WebRtc_UWord16 maxDataPayloadLength = _rtpRtcp.MaxDataPayloadLength(); + if (_vcm.RegisterSendCodec(¤tSendCodec, _numberOfCores, + maxDataPayloadLength) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "Could not use internal encoder"); + return -1; + } + } + return 0; +} + +// ---------------------------------------------------------------------------- +// SetEncoder +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::SetEncoder(const webrtc::VideoCodec& videoCodec) +{ + WEBRTC_TRACE( webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: CodecType: %d, width: %u, height: %u, maxPayloadLength: %u", + __FUNCTION__, videoCodec.codecType, videoCodec.width, + videoCodec.height); + + // Multiply startBitrate by 1000 because RTP module changed in API. + if (_rtpRtcp.SetSendBitrate(videoCodec.startBitrate * 1000, + videoCodec.minBitrate, videoCodec.maxBitrate) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Could not set RTP module bitrates"); + return -1; + } + + // Setting target width and height for VPM + if (_vpm.SetTargetResolution(videoCodec.width, videoCodec.height, videoCodec.maxFramerate) != VPM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Could not set VPM target dimensions"); + return -1; + + } + + if (_rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Could register RTP module video payload"); + return -1; + } + + WebRtc_UWord16 maxDataPayloadLength = _rtpRtcp.MaxDataPayloadLength(); + + // update QM with MaxDataPayloadLength + _qmCallback->SetMaxPayloadLength(maxDataPayloadLength); + + if (_vcm.RegisterSendCodec(&videoCodec, _numberOfCores, + maxDataPayloadLength) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Could not register send codec"); + return -1; + } + _dataCritsect.Enter(); + memcpy(&_sendCodec, &videoCodec, sizeof(_sendCodec)); // Copy current send codec + _dataCritsect.Leave(); + + // Set this module as sending right away, let the + // slave module in the channel start and stop sending... + if (_rtpRtcp.Sending() == false) + { + if (_rtpRtcp.SetSendingStatus(true) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "Could start RTP module sending"); + return -1; + } + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetSendCodec +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::GetEncoder(webrtc::VideoCodec& videoCodec) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_vcm.SendCodec(&videoCodec) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "Could not get VCM send codec"); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetCodecConfigParameters +// +// Only valid for H.264 and MPEG-4 +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::GetCodecConfigParameters( + unsigned char configParameters[kConfigParameterSize], + unsigned char& configParametersSize) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + WebRtc_Word32 numParameters = + _vcm.CodecConfigParameters(configParameters, kConfigParameterSize); + if (numParameters <= 0) + { + configParametersSize = 0; + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Could not get config parameters"); + return -1; + } + configParametersSize = (unsigned char) numParameters; + return 0; +} + +// ---------------------------------------------------------------------------- +// ScaleInputImage +// +// The input image will be scaled if the codec resolution differs from the +// image resolution of the input image, otherwise will the image be +// cropped/padded. Default: crop/pad. +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::ScaleInputImage(bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(enable %d)", __FUNCTION__, enable); + + VideoFrameResampling resamplingMode = kFastRescaling; + if (enable == true) + { + // Currently not supported. + //resamplingMode = kInterpolation; + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s not supported", + __FUNCTION__, enable); + return -1; + } + _vpm.SetInputFrameResampleMode(resamplingMode); + + return 0; +} + +//============================================================================= +// RTP settings +//============================================================================= + +// ---------------------------------------------------------------------------- +// GetRtpRtcpModule +// ---------------------------------------------------------------------------- + +RtpRtcp* ViEEncoder::SendRtpRtcpModule() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + return &_rtpRtcp; +} + +//============================================================================= +// Data flow +//============================================================================= + + +// ---------------------------------------------------------------------------- +// DeliverFrame +// Implements ViEFrameCallback::DeliverFrame +// Receive videoFrame to be encoded from a provider (capture or file) +// ---------------------------------------------------------------------------- + +void ViEEncoder::DeliverFrame(int id, webrtc::VideoFrame& videoFrame, + int numCSRCs, + const WebRtc_UWord32 CSRC[kRtpCsrcSize]) +{ + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: %llu", __FUNCTION__, videoFrame.TimeStamp()); + + { + CriticalSectionScoped cs(_dataCritsect); + if (_paused || _rtpRtcp.SendingMedia() == false) + { + // We've passed or we have no channels attached, don't encode + return; + } + if (_dropNextFrame) + { + // Drop this frame + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: Dropping frame %llu after a key fame", + __FUNCTION__, videoFrame.TimeStamp()); + _dropNextFrame = false; + return; + } + } + // Set the frame timestamp + const WebRtc_UWord32 timeStamp = 90 * (WebRtc_UWord32) videoFrame.RenderTimeMs(); + videoFrame.SetTimeStamp(timeStamp); + { + // Send to effect filter, if registered by user. + CriticalSectionScoped cs(_callbackCritsect); + if (_effectFilter) + { + _effectFilter->Transform(videoFrame.Length(), videoFrame.Buffer(), + videoFrame.TimeStamp(), + videoFrame.Width(), videoFrame.Height()); + } + } + // Record un-encoded frame. + _fileRecorder.RecordVideoFrame(videoFrame); + // Make sure the CSRC list is correct. + if (numCSRCs > 0) + { + WebRtc_UWord32 tempCSRC[kRtpCsrcSize]; + for (int i = 0; i < numCSRCs; i++) + { + if (CSRC[i] == 1) + { + tempCSRC[i] = _rtpRtcp.SSRC(); + } + else + { + tempCSRC[i] = CSRC[i]; + } + } + _rtpRtcp.SetCSRCs(tempCSRC, (WebRtc_UWord8) numCSRCs); + } + +#ifdef VIDEOCODEC_VP8 + if (_vcm.SendCodec() == webrtc::kVideoCodecVP8) + { + webrtc::CodecSpecificInfo codecSpecificInfo; + codecSpecificInfo.codecType = webrtc::kVideoCodecUnknown; + + if (_hasReceivedSLI || _hasReceivedRPSI) + { + webrtc::VideoCodec currentSendCodec; + _vcm.SendCodec(¤tSendCodec); + if (currentSendCodec.codecType == webrtc::kVideoCodecVP8) + { + codecSpecificInfo.codecType = webrtc::kVideoCodecVP8; + codecSpecificInfo.codecSpecific.VP8.hasReceivedRPSI = _hasReceivedRPSI; + codecSpecificInfo.codecSpecific.VP8.hasReceivedSLI = _hasReceivedSLI; + codecSpecificInfo.codecSpecific.VP8.pictureIdRPSI = _pictureIdRPSI; + codecSpecificInfo.codecSpecific.VP8.pictureIdSLI = _pictureIdSLI; + } + _hasReceivedSLI = false; + _hasReceivedRPSI = false; + } + // Pass frame via preprocessor + VideoFrame *decimatedFrame = NULL; + const int ret = _vpm.PreprocessFrame(&videoFrame, &decimatedFrame); + if (ret == 1) + { + // Drop this frame + return; + } + else if (ret != VPM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: Error preprocessing frame %u", __FUNCTION__, + videoFrame.TimeStamp()); + return; + } + + VideoContentMetrics* contentMetrics = NULL; + contentMetrics = _vpm.ContentMetrics(); + + if (_vcm.AddVideoFrame + (*decimatedFrame, contentMetrics, &codecSpecificInfo) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: Error encoding frame %u", __FUNCTION__, + videoFrame.TimeStamp()); + } + return; + } +#endif + // Pass frame via preprocessor + VideoFrame *decimatedFrame = NULL; + const int ret = _vpm.PreprocessFrame(&videoFrame, &decimatedFrame); + if (ret == 1) + { + // Drop this frame + return; + } + else if (ret != VPM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: Error preprocessing frame %u", __FUNCTION__, videoFrame.TimeStamp()); + return; + } + if (_vcm.AddVideoFrame(*decimatedFrame) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: Error encoding frame %u", + __FUNCTION__, videoFrame.TimeStamp()); + } +} +// ---------------------------------------------------------------------------- +// DeliverFrame +// Implements ViEFrameCallback::DelayChanged +// ---------------------------------------------------------------------------- +void ViEEncoder::DelayChanged(int id, int frameDelay) + +{ + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: %u", __FUNCTION__, frameDelay); + + _rtpRtcp.SetCameraDelay(frameDelay); + _fileRecorder.SetFrameDelay(frameDelay); +} +// ---------------------------------------------------------------------------- +// GetPreferedFrameSettings +// Implements ViEFrameCallback::GetPreferedFrameSettings +// Fetch the widh, height and frame rate prefered by this encoder. +// ---------------------------------------------------------------------------- + +int ViEEncoder::GetPreferedFrameSettings(int &width, int &height, + int &frameRate) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + webrtc::VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(videoCodec)); + if (_vcm.SendCodec(&videoCodec) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "Could not get VCM send codec"); + return -1; + } + + width = videoCodec.width; + height = videoCodec.height; + frameRate = videoCodec.maxFramerate; + return 0; + +} +// ---------------------------------------------------------------------------- +// SendKeyFrame +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::SendKeyFrame() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + return _vcm.FrameTypeRequest(kVideoFrameKey); +} + +// ---------------------------------------------------------------------------- +// SendCodecStatistics +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::SendCodecStatistics(WebRtc_UWord32& numKeyFrames, + WebRtc_UWord32& numDeltaFrames) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + webrtc::VCMFrameCount sentFrames; + if (_vcm.SentFrameCount(sentFrames) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not get sent frame information", __FUNCTION__); + return -1; + } + numKeyFrames = sentFrames.numKeyFrames; + numDeltaFrames = sentFrames.numDeltaFrames; + return 0; + +} + +//============================================================================= +// Loss protection +//============================================================================= + +// ---------------------------------------------------------------------------- +// UpdateProtectionMethod +// +// Updated protection method to VCM to get correct packetization sizes +// FEC has larger overhead than NACK -> set FEC if used +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::UpdateProtectionMethod() +{ + // Get FEC status + bool fecEnabled = false; + WebRtc_UWord8 dummyPTypeRed = 0; + WebRtc_UWord8 dummyPTypeFEC = 0; + + WebRtc_Word32 error = _rtpRtcp.GenericFECStatus(fecEnabled, dummyPTypeRed, + dummyPTypeFEC); + if (error) + { + return -1; + } + + if (_fecEnabled != fecEnabled) + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: FEC status ", __FUNCTION__, fecEnabled); + + _vcm.SetVideoProtection(webrtc::kProtectionFEC, fecEnabled); + if (fecEnabled) + { + _vcm.RegisterProtectionCallback(this); + } else + { + _vcm.RegisterProtectionCallback(NULL); + } + // Need to reregister the send codec in order to set the new MTU + webrtc::VideoCodec codec; + if (_vcm.SendCodec(&codec) == 0) + { + WebRtc_UWord16 maxPayLoad = _rtpRtcp.MaxDataPayloadLength(); + codec.startBitrate = _vcm.Bitrate(); + if (_vcm.RegisterSendCodec(&codec, _numberOfCores, maxPayLoad) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: Failed to update Sendcodec when enabling FEC", + __FUNCTION__, fecEnabled); + return -1; + } + } + _fecEnabled = fecEnabled; + } + + // Update NACK status + _vcm.SetVideoProtection(webrtc::kProtectionNack, _rtpRtcp.NACK() != kNackOff); + + return 0; +} + +//============================================================================= +// Implementation of VideoPacketizationCallback from VCM +//============================================================================= + +// ---------------------------------------------------------------------------- +// SendData +// ---------------------------------------------------------------------------- +WebRtc_Word32 ViEEncoder::SendData(const FrameType frameType, + const WebRtc_UWord8 payloadType, + const WebRtc_UWord32 timeStamp, + const WebRtc_UWord8* payloadData, + const WebRtc_UWord32 payloadSize, + const webrtc::RTPFragmentationHeader& fragmentationHeader) +{ + { + CriticalSectionScoped cs(_dataCritsect); + if (_paused) + { + // Paused, don't send this packet + return 0; + } + if (_channelsDroppingDeltaFrames && frameType == webrtc::kVideoFrameKey) + { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: Sending key frame, drop next frame", __FUNCTION__); + _dropNextFrame = true; + } + } + // New encoded data, hand over to the rtp module + WebRtc_Word32 retVal = _rtpRtcp.SendOutgoingData(frameType, payloadType, + timeStamp, payloadData, + payloadSize, + &fragmentationHeader); + return retVal; +} + +//============================================================================= +// Implementation of VideoProtectionCallback from VCM +//============================================================================= + +// ---------------------------------------------------------------------------- +// ProtectionRequest +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::ProtectionRequest(const WebRtc_UWord8 deltaFECRate, + const WebRtc_UWord8 keyFECRate, + const bool nack) +{ + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: deltaFECRate: %u, keyFECRate: %u, nack: %d", __FUNCTION__, + deltaFECRate, keyFECRate, nack); + + if (_rtpRtcp.SetFECCodeRate(keyFECRate, deltaFECRate) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not update FEC code rate", __FUNCTION__); + } + return 0; +} + +//============================================================================= +// Implementation of VideoSendStatisticsCallback from VCM +//============================================================================= + +// ---------------------------------------------------------------------------- +// SendStatistics +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::SendStatistics(const WebRtc_UWord32 bitRate, + const WebRtc_UWord32 frameRate) +{ + CriticalSectionScoped cs(_callbackCritsect); + if (_codecObserver) + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: bitrate %u, framerate %u", __FUNCTION__, bitRate, + frameRate); + _codecObserver->OutgoingRate(_channelId, frameRate, bitRate); + } + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterCodecObserver +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViEEncoder::RegisterCodecObserver(ViEEncoderObserver* observer) +{ + CriticalSectionScoped cs(_callbackCritsect); + if (observer) + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: observer added", __FUNCTION__); + if (_codecObserver) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: observer already set.", __FUNCTION__); + return -1; + } + _codecObserver = observer; + } else + { + if (_codecObserver == NULL) + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: observer does not exist.", __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: observer removed", __FUNCTION__); + _codecObserver = NULL; + } + return 0; +} + +//============================================================================= +// Implementation of RtcpFeedback +//============================================================================= + +void ViEEncoder::OnSLIReceived(const WebRtc_Word32 id, + const WebRtc_UWord8 pictureId) +{ + _pictureIdSLI = pictureId; + _hasReceivedSLI = true; +} + +void ViEEncoder::OnRPSIReceived(const WebRtc_Word32 id, + const WebRtc_UWord64 pictureId) +{ + _pictureIdRPSI = pictureId; + _hasReceivedRPSI = true; +} + +//============================================================================= +// Implementation of RtpVideoFeedback +//============================================================================= + +// ---------------------------------------------------------------------------- +// OnReceivedIntraFrameRequest +// ---------------------------------------------------------------------------- + +void ViEEncoder::OnReceivedIntraFrameRequest(const WebRtc_Word32 id, + const WebRtc_UWord8 message) +{ + // Key frame request from other side, signal to VCM + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s", __FUNCTION__); + + if (_timeLastIntraRequestMs + kViEMinKeyRequestIntervalMs + > TickTime::MillisecondTimestamp()) + { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Not not encoding new intra due to timing", __FUNCTION__); + return; + } + // Default message == 0... + if (message == 0) + { + _vcm.FrameTypeRequest(kVideoFrameKey); + } else + { + _vcm.FrameTypeRequest((FrameType) message); + } + _timeLastIntraRequestMs = TickTime::MillisecondTimestamp(); + return; +} + +// ---------------------------------------------------------------------------- +// OnNetworkChanged +// ---------------------------------------------------------------------------- +void ViEEncoder::OnNetworkChanged(const WebRtc_Word32 id, + const WebRtc_UWord32 minBitrateBps, + const WebRtc_UWord32 maxBitrateBps, + const WebRtc_UWord8 fractionLost, + const WebRtc_UWord16 roundTripTimeMs, + const WebRtc_UWord16 bwEstimateKbitMin, + const WebRtc_UWord16 bwEstimateKbitMax) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s(minBitrateBps: %u, maxBitrateBps: %u,fractionLost: %u, rttMs: %u, bwEstMinKbit: %u, bwEstMaxKbit: %u", + __FUNCTION__, minBitrateBps, maxBitrateBps, fractionLost, + roundTripTimeMs, bwEstimateKbitMin, bwEstimateKbitMax); + _vcm.SetChannelParameters(minBitrateBps / 1000, fractionLost, roundTripTimeMs); + return; +} + +WebRtc_Word32 ViEEncoder::RegisterEffectFilter(ViEEffectFilter* effectFilter) +{ + CriticalSectionScoped cs(_callbackCritsect); + if (effectFilter == NULL) + { + if (_effectFilter == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: no effect filter added", __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: deregister effect filter", __FUNCTION__); + } else + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + "%s: register effect", __FUNCTION__); + if (_effectFilter) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: effect filter already added ", __FUNCTION__); + return -1; + } + } + _effectFilter = effectFilter; + return 0; +} + +ViEFileRecorder& ViEEncoder::GetOutgoingFileRecorder() +{ + return _fileRecorder; +} + +//============================================================================= +// Implementation of Video QM settings callback: +// Callback to be called from VCM to update VPM of frame rate and size +//============================================================================= + +ViEEncoder::QMTestVideoSettingsCallback::QMTestVideoSettingsCallback(): +_vpm(NULL), +_vcm(NULL) +{ + +} + +void ViEEncoder::QMTestVideoSettingsCallback:: + RegisterVPM(VideoProcessingModule *vpm) +{ + _vpm = vpm; +} + +void ViEEncoder::QMTestVideoSettingsCallback:: + RegisterVCM(VideoCodingModule *vcm) +{ + _vcm = vcm; +} + +WebRtc_Word32 ViEEncoder::QMTestVideoSettingsCallback::SetVideoQMSettings + (const WebRtc_UWord32 frameRate, + const WebRtc_UWord32 width, + const WebRtc_UWord32 height) +{ + + WebRtc_Word32 retVal = 0; + retVal = _vpm->SetTargetResolution(width, height, frameRate); + //Initialize codec with new values + if (!retVal) + { + // first get current settings + VideoCodec currentCodec; + _vcm->SendCodec(¤tCodec); + + WebRtc_UWord32 currentBitRate = _vcm->Bitrate(); + + // now set new values: + currentCodec.height = (WebRtc_UWord16)height; + currentCodec.width = (WebRtc_UWord16)width; + currentCodec.maxFramerate = (WebRtc_UWord8)frameRate; + currentCodec.startBitrate = currentBitRate; + + // re-register encoder + retVal = _vcm->RegisterSendCodec(¤tCodec,_numOfCores,_maxPayloadLength); + } + + return retVal; +} + +///////////////////// + + +} // namespace webrtc diff --git a/video_engine/main/source/vie_encoder.h b/video_engine/main/source/vie_encoder.h new file mode 100644 index 0000000000..42d297818a --- /dev/null +++ b/video_engine/main/source/vie_encoder.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_encoder.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_ENCODER_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_ENCODER_H_ + +#include "vie_defines.h" +#include "typedefs.h" +#include "vie_frame_provider_base.h" +#include "vie_file_recorder.h" +#include "rtp_rtcp_defines.h" +#include "video_coding_defines.h" +#include "video_processing.h" +#include "common_types.h" + +namespace webrtc { +class CriticalSectionWrapper; +class ProcessThread; +class RtpRtcp; +class ViEEffectFilter; +class VideoCodingModule; +class ViEEncoderObserver; + +class ViEEncoder: public ViEFrameCallback, // New frame delivery + public RtpVideoFeedback, // Feedback from RTP module + public RtcpFeedback, // RTP/RTCP Module + public VCMPacketizationCallback, // Callback from VCM + public VCMProtectionCallback, // Callback from VCM + public VCMSendStatisticsCallback // Callback from VCM +{ +public: + ViEEncoder(WebRtc_Word32 engineId, WebRtc_Word32 channelId, + WebRtc_UWord32 numberOfCores, + ProcessThread& moduleProcessThread); + ~ViEEncoder(); + + // Drops incoming packets + void Pause(); + void Restart(); + + WebRtc_Word32 DropDeltaAfterKey(bool enable); + + // Codec settings + WebRtc_UWord8 NumberOfCodecs(); + WebRtc_Word32 GetCodec(WebRtc_UWord8 listIndex, VideoCodec& videoCodec); + WebRtc_Word32 RegisterExternalEncoder(VideoEncoder* encoder, + WebRtc_UWord8 plType); + WebRtc_Word32 DeRegisterExternalEncoder(WebRtc_UWord8 plType); + WebRtc_Word32 SetEncoder(const VideoCodec& videoCodec); + WebRtc_Word32 GetEncoder(VideoCodec& videoCodec); + + WebRtc_Word32 GetCodecConfigParameters( + unsigned char configParameters[kConfigParameterSize], + unsigned char& configParametersSize); + + // Scale or crop/pad image + WebRtc_Word32 ScaleInputImage(bool enable); + + // RTP settings + RtpRtcp* SendRtpRtcpModule(); + + // Implementing ViEFrameCallback + virtual void DeliverFrame(int id, VideoFrame& videoFrame, int numCSRCs = 0, + const WebRtc_UWord32 CSRC[kRtpCsrcSize] = NULL); + virtual void DelayChanged(int id, int frameDelay); + virtual int GetPreferedFrameSettings(int &width, int &height, + int &frameRate); + + virtual void ProviderDestroyed(int id) { return; } + + WebRtc_Word32 EncodeFrame(VideoFrame& videoFrame); + WebRtc_Word32 SendKeyFrame(); + WebRtc_Word32 SendCodecStatistics(WebRtc_UWord32& numKeyFrames, + WebRtc_UWord32& numDeltaFrames); + // Loss protection + WebRtc_Word32 UpdateProtectionMethod(); + // Implements VCMPacketizationCallback + virtual WebRtc_Word32 SendData(const FrameType frameType, + const WebRtc_UWord8 payloadType, + const WebRtc_UWord32 timeStamp, + const WebRtc_UWord8* payloadData, + const WebRtc_UWord32 payloadSize, + const RTPFragmentationHeader& fragmentationHeader); + // Implements VideoProtectionCallback + virtual WebRtc_Word32 ProtectionRequest(const WebRtc_UWord8 deltaFECRate, + const WebRtc_UWord8 keyFECRate, + const bool nack); + // Implements VideoSendStatisticsCallback + virtual WebRtc_Word32 SendStatistics(const WebRtc_UWord32 bitRate, + const WebRtc_UWord32 frameRate); + WebRtc_Word32 RegisterCodecObserver(ViEEncoderObserver* observer); + // Implements RtcpFeedback + virtual void OnSLIReceived(const WebRtc_Word32 id, + const WebRtc_UWord8 pictureId); + virtual void OnRPSIReceived(const WebRtc_Word32 id, + const WebRtc_UWord64 pictureId); + + // Implements RtpVideoFeedback + virtual void OnReceivedIntraFrameRequest(const WebRtc_Word32 id, + const WebRtc_UWord8 message = 0); + virtual void OnNetworkChanged(const WebRtc_Word32 id, + const WebRtc_UWord32 minBitrateBps, + const WebRtc_UWord32 maxBitrateBps, + const WebRtc_UWord8 fractionLost, + const WebRtc_UWord16 roundTripTimeMs, + const WebRtc_UWord16 bwEstimateKbitMin, + const WebRtc_UWord16 bwEstimateKbitMax); + // Effect filter + WebRtc_Word32 RegisterEffectFilter(ViEEffectFilter* effectFilter); + //Recording + ViEFileRecorder& GetOutgoingFileRecorder(); + +private: + WebRtc_Word32 _engineId; + + class QMTestVideoSettingsCallback : public VCMQMSettingsCallback + { + public: + QMTestVideoSettingsCallback(); + // update VPM with QM (quality modes: frame size & frame rate) settings + WebRtc_Word32 SetVideoQMSettings(const WebRtc_UWord32 frameRate, + const WebRtc_UWord32 width, + const WebRtc_UWord32 height); + // register VPM and VCM + void RegisterVPM(VideoProcessingModule* vpm); + void RegisterVCM(VideoCodingModule* vcm); + void SetNumOfCores(WebRtc_Word32 numOfCores) + {_numOfCores = numOfCores;}; + void SetMaxPayloadLength(WebRtc_Word32 maxPayloadLength) + {_maxPayloadLength = maxPayloadLength;}; + private: + VideoProcessingModule* _vpm; + VideoCodingModule* _vcm; + WebRtc_Word32 _numOfCores; + WebRtc_Word32 _maxPayloadLength; + }; + + WebRtc_Word32 _channelId; + const WebRtc_UWord32 _numberOfCores; + + VideoCodingModule& _vcm; + VideoProcessingModule& _vpm; + RtpRtcp& _rtpRtcp; + CriticalSectionWrapper& _callbackCritsect; + CriticalSectionWrapper& _dataCritsect; + VideoCodec _sendCodec; + + bool _paused; + WebRtc_Word64 _timeLastIntraRequestMs; + WebRtc_Word32 _channelsDroppingDeltaFrames; + bool _dropNextFrame; + //Loss protection + bool _fecEnabled; + // Uses + ViEEncoderObserver* _codecObserver; + ViEEffectFilter* _effectFilter; + ProcessThread& _moduleProcessThread; + + bool _hasReceivedSLI; + WebRtc_UWord8 _pictureIdSLI; + bool _hasReceivedRPSI; + WebRtc_UWord64 _pictureIdRPSI; + + //Recording + ViEFileRecorder _fileRecorder; + + // Quality modes callback + QMTestVideoSettingsCallback* _qmCallback; + +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_ENCODER_H_ diff --git a/video_engine/main/source/vie_encryption_impl.cc b/video_engine/main/source/vie_encryption_impl.cc new file mode 100644 index 0000000000..6a96128527 --- /dev/null +++ b/video_engine/main/source/vie_encryption_impl.cc @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_encryption_impl.cc + */ + +#include "vie_encryption_impl.h" + +// Defines +#include "vie_defines.h" +#include "vie_errors.h" +#include "vie_channel.h" +#include "vie_channel_manager.h" + +#include "trace.h" +#include "vie_impl.h" + +#ifdef WEBRTC_SRTP +#include "SrtpModule.h" +#endif + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// GetInterface +// ---------------------------------------------------------------------------- + +ViEEncryption* ViEEncryption::GetInterface(VideoEngine* videoEngine) +{ +#ifdef WEBRTC_VIDEO_ENGINE_ENCRYPTION_API + if (videoEngine == NULL) + { + return NULL; + } + VideoEngineImpl* vieImpl = reinterpret_cast (videoEngine); + ViEEncryptionImpl* vieEncryptionImpl = vieImpl; + (*vieEncryptionImpl)++; // Increase ref count + + return vieEncryptionImpl; +#else + return NULL; +#endif +} + +// ---------------------------------------------------------------------------- +// Release +// +// Releases the interface, i.e. reduces the reference counter. The number of +// remaining references is returned, -1 if released too many times. +// ---------------------------------------------------------------------------- + +int ViEEncryptionImpl::Release() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "ViEEncryptionImpl::Release()"); + (*this)--; // Decrease ref count + + WebRtc_Word32 refCount = GetCount(); + if (refCount < 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, + "ViEEncryptionImpl release too many times"); + SetLastError(kViEAPIDoesNotExist); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId, + "ViEEncryptionImpl reference count: %d", refCount); + return refCount; +} + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViEEncryptionImpl::ViEEncryptionImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViEEncryptionImpl::ViEEncryptionImpl() Ctor"); +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViEEncryptionImpl::~ViEEncryptionImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViEEncryptionImpl::~ViEEncryptionImpl() Dtor"); +} + +// ============================================================================ +// SRTP +// ============================================================================ + +// ---------------------------------------------------------------------------- +// EnableSRTPSend +// +// ---------------------------------------------------------------------------- + +int ViEEncryptionImpl::EnableSRTPSend( + const int videoChannel, const CipherTypes cipherType, + const unsigned int cipherKeyLength, const AuthenticationTypes authType, + const unsigned int authKeyLength, const unsigned int authTagLength, + const SecurityLevels level, const unsigned char key[kViEMaxSrtpKeyLength], + const bool useForRTCP) +{ + + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "EnableSRTPSend(channel=%d, cipherType=%d, cipherKeyLength=%d, " + "authType=%d, authKeyLength=%d, authTagLength=%d, level=%d, " + "key=?, RTCP=%s", + videoChannel, cipherType, cipherKeyLength, authType, + authKeyLength, authTagLength, level, + useForRTCP ? "true" : "false"); +#ifdef WEBRTC_SRTP + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + bool cipherAllZero = (kCipherNull == cipherType) && (0 == cipherKeyLength); + bool authAllZero = (kAuthNull == authType) && + (0 == authKeyLength) && + (0 == authTagLength); + + // 1. For no protection all cipher and auth must be zero + // 2. For encryption only all auth must be zero + // 3. For authentication only all cipher must be zero + if (((kNoProtection == level) && (!cipherAllZero || !authAllZero)) + || ((kEncryption == level) && !authAllZero) + || ((kAuthentication == level) && !cipherAllZero)) + + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + " Invalid input argument"); + SetLastError(kViEEncryptionInvalidSrtpParameter); + return -1; + } + + // 16 <= cipherKeyLength <= 256 + if (((kEncryption == level) || (kEncryptionAndAuthentication == level)) + && ((cipherKeyLength < kViEMinSrtpEncryptLength) + || (cipherKeyLength > kViEMaxSrtpEncryptLength))) + + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + " Invalid cipher key length"); + SetLastError(kViEEncryptionInvalidSrtpParameter); + return -1; + } + + // For HMAC_SHA1 auth: + // authKeyLength <= 20, authTagLength <= 20 + if (((kAuthentication == level) || (kEncryptionAndAuthentication == level)) + && (kAuthHmacSha1 == authType) + && ((authKeyLength > kViEMaxSrtpAuthSh1Length) + || (authTagLength > kViEMaxSrtpAuthSh1Length))) + + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + " Invalid auth key or tag length"); + SetLastError(kViEEncryptionInvalidSrtpParameter); + return -1; + } + + // For NULL auth: + // authKeyLength <= 256, authTagLength <= 12 + if (((kAuthentication == level) || (kEncryptionAndAuthentication == level)) + && (kAuthNull == authType) + && ((authKeyLength > kViEMaxSrtpKeyAuthNullLength) + || (authTagLength > kViEMaxSrtpTagAuthNullLength))) + + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + " Invalid auth key or tag length"); + SetLastError(kViEEncryptionInvalidSrtpParameter); + return -1; + } + if (!key) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + " key NULL pointer"); + SetLastError(kViEEncryptionInvalidSrtpParameter); + return -1; + } + + const SrtpModule::CipherTypes cipher_type = + static_cast (cipherType); + const SrtpModule::AuthenticationTypes auth_type = + static_cast (authType); + const SrtpModule::SecurityLevels security_level = + static_cast (level); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViEEncryptionInvalidChannelId); + return -1; + } + + if (0 != vieChannel->EnableSRTPSend(cipher_type, cipherKeyLength, auth_type, + authKeyLength, authTagLength, + security_level, key, useForRTCP)) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + "Failed to configure SRTP Encryption for sending"); + SetLastError(kViEEncryptionUnknownError); + return -1; + } + + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, _instanceId, + "SRTP Enabled for sending"); + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVoice, + ViEId(_instanceId, videoChannel), + " _SRTP is undefined => _lastError = %d", + LastErrorInternal()); + SetLastError(kViEEncryptionSrtpNotSupported); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// DisableSRTPSend +// +// ---------------------------------------------------------------------------- + +int ViEEncryptionImpl::DisableSRTPSend(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "DisableSRTPSend(videoChannel=%d)", videoChannel); +#ifdef WEBRTC_SRTP + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViEEncryptionInvalidChannelId); + return -1; + } + + if (0 != vieChannel->DisableSRTPSend()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "Failed to Disable SRTP Encryption for sending"); + SetLastError(kViEEncryptionUnknownError); + return -1; + } + + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "SRTP Disabled for sending"); + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVoice, + ViEId(_instanceId, videoChannel), + " _SRTP is undefined => _lastError = %d", + LastErrorInternal()); + SetLastError(kViEEncryptionSrtpNotSupported); + return -1; +#endif + +} + +// ---------------------------------------------------------------------------- +// EnableSRTPReceive +// +// ---------------------------------------------------------------------------- + +int ViEEncryptionImpl::EnableSRTPReceive( + const int videoChannel, const CipherTypes cipherType, + const unsigned int cipherKeyLength, const AuthenticationTypes authType, + const unsigned int authKeyLength, const unsigned int authTagLength, + const SecurityLevels level, + const unsigned char key[kViEMaxSrtpKeyLength], const bool useForRTCP) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "EnableSRTPReceive(channel=%d, cipherType=%d, " + "cipherKeyLength=%d, authType=%d, authKeyLength=%d, " + "authTagLength=%d, level=%d, key=?, RTCP=%s)", + videoChannel, cipherType, cipherKeyLength, authType, + authKeyLength, authTagLength, level, + useForRTCP ? "true" : "false"); + +#ifdef WEBRTC_SRTP + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + bool cipherAllZero = (kCipherNull == cipherType) && (0 == cipherKeyLength); + bool authAllZero = (kAuthNull == authType) + && (0 == authKeyLength) + && (0 == authTagLength); + + // 1. For no protection all cipher and auth must be zero + // 2. For encryption only all auth must be zero + // 3. For authentication only all cipher must be zero + if (((kNoProtection == level) && (!cipherAllZero || !authAllZero)) || + ((kEncryption == level) && !authAllZero) || + ((kAuthentication == level) && !cipherAllZero)) + + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + " Invalid input argument"); + SetLastError(kViEEncryptionInvalidSrtpParameter); + return -1; + } + + // 16 <= cipherKeyLength <= 256 + if (((kEncryption == level) || (kEncryptionAndAuthentication == level)) + && ((cipherKeyLength < kViEMinSrtpEncryptLength) + || (cipherKeyLength > kViEMaxSrtpEncryptLength))) + + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + " Invalid cipher key length"); + SetLastError(kViEEncryptionInvalidSrtpParameter); + return -1; + } + + // For HMAC_SHA1 auth: + // authKeyLength <= 20, authTagLength <= 20 + if (((kAuthentication == level) || (kEncryptionAndAuthentication == level)) + && (kAuthHmacSha1 == authType) + && ((authKeyLength > kViEMaxSrtpAuthSh1Length) + || (authTagLength > kViEMaxSrtpAuthSh1Length))) + + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + " Invalid auth key or tag length"); + SetLastError(kViEEncryptionInvalidSrtpParameter); + return -1; + } + + // For NULL auth: + // authKeyLength <= 256, authTagLength <= 12 + if (((kAuthentication == level) || (kEncryptionAndAuthentication == level)) + && (kAuthNull == authType) + && ((authKeyLength > kViEMaxSrtpKeyAuthNullLength) + || (authTagLength > kViEMaxSrtpTagAuthNullLength))) + + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + " Invalid auth key or tag length"); + SetLastError(kViEEncryptionInvalidSrtpParameter); + return -1; + } + + if (!key) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), " key NULL pointer"); + SetLastError(kViEEncryptionInvalidSrtpParameter); + return -1; + } + + const SrtpModule::CipherTypes cipher_type = + static_cast (cipherType); + const SrtpModule::AuthenticationTypes auth_type = + static_cast (authType); + const SrtpModule::SecurityLevels security_level = + static_cast (level); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViEEncryptionInvalidChannelId); + return -1; + } + + if (0 != vieChannel->EnableSRTPReceive(cipher_type, cipherKeyLength, + auth_type, authKeyLength, + authTagLength, security_level, key, + useForRTCP)) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "Failed to configure SRTP Encryption for receiving"); + SetLastError(kViEEncryptionUnknownError); + return -1; + } + + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "SRTP Enabled for receiving"); + return 0; + +#else + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVoice, + ViEId(_instanceId, videoChannel), + " _SRTP is undefined => _lastError = %d", + LastErrorInternal()); + SetLastError(kViEEncryptionSrtpNotSupported); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// DisableSRTPReceive +// +// ---------------------------------------------------------------------------- + +int ViEEncryptionImpl::DisableSRTPReceive(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "DisableSRTPReceive(videoChannel=%d)", videoChannel); + +#ifdef WEBRTC_SRTP + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViEEncryptionInvalidChannelId); + return -1; + } + + if (0 != vieChannel->DisableSRTPReceive()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "Failed to Disable SRTP Encryption for receiving"); + SetLastError(kViEEncryptionUnknownError); + return -1; + } + + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "SRTP Disabled for receiving"); + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVoice, + ViEId(_instanceId, videoChannel), + " _SRTP is undefined => _lastError = %d", + LastErrorInternal()); + SetLastError(kViEEncryptionSrtpNotSupported); + return -1; +#endif +} + +// ============================================================================ +// External encryption +// ============================================================================ + +// ---------------------------------------------------------------------------- +// RegisterExternalEncryption +// +// ---------------------------------------------------------------------------- + +int ViEEncryptionImpl::RegisterExternalEncryption(const int videoChannel, + Encryption& encryption) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "RegisterExternalEncryption(videoChannel=%d)", videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViEEncryptionInvalidChannelId); + return -1; + } + if (vieChannel->RegisterExternalEncryption(&encryption) != 0) + { + SetLastError(kViEEncryptionUnknownError); + return -1; + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterExternalEncryption +// +// ---------------------------------------------------------------------------- + +int ViEEncryptionImpl::DeregisterExternalEncryption(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "RegisterExternalEncryption(videoChannel=%d)", videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: No channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViEEncryptionInvalidChannelId); + return -1; + } + + if (vieChannel->DeRegisterExternalEncryption() != 0) + { + SetLastError(kViEEncryptionUnknownError); + return -1; + } + return 0; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_encryption_impl.h b/video_engine/main/source/vie_encryption_impl.h new file mode 100644 index 0000000000..2a306d0a60 --- /dev/null +++ b/video_engine/main/source/vie_encryption_impl.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_encryption_impl.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_ENCRYPTION_IMPL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_ENCRYPTION_IMPL_H_ + +#include "vie_defines.h" + +#include "typedefs.h" +#include "vie_ref_count.h" +#include "vie_encryption.h" +#include "vie_shared_data.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// ViEEncryptionImpl +// ---------------------------------------------------------------------------- + +class ViEEncryptionImpl : public virtual ViESharedData, + public ViEEncryption, + public ViERefCount +{ +public: + virtual int Release(); + + // SRTP calls + virtual int EnableSRTPSend(const int videoChannel, + const CipherTypes cipherType, + const unsigned int cipherKeyLength, + const AuthenticationTypes authType, + const unsigned int authKeyLength, + const unsigned int authTagLength, + const SecurityLevels level, + const unsigned char key[kViEMaxSrtpKeyLength], + const bool useForRTCP); + + virtual int DisableSRTPSend(const int videoChannel); + + virtual int EnableSRTPReceive(const int videoChannel, + const CipherTypes cipherType, + const unsigned int cipherKeyLength, + const AuthenticationTypes authType, + const unsigned int authKeyLength, + const unsigned int authTagLength, + const SecurityLevels level, + const unsigned char key[kViEMaxSrtpKeyLength], + const bool useForRTCP); + + virtual int DisableSRTPReceive(const int videoChannel); + + // External encryption + virtual int RegisterExternalEncryption(const int videoChannel, + Encryption& encryption); + + virtual int DeregisterExternalEncryption(const int videoChannel); + +protected: + ViEEncryptionImpl(); + virtual ~ViEEncryptionImpl(); +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_ENCRYPTION_IMPL_H_ diff --git a/video_engine/main/source/vie_external_codec_impl.cc b/video_engine/main/source/vie_external_codec_impl.cc new file mode 100644 index 0000000000..beeb72c35e --- /dev/null +++ b/video_engine/main/source/vie_external_codec_impl.cc @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_external_codec_impl.cc + */ + +#include "engine_configurations.h" +#include "vie_external_codec_impl.h" +#include "vie_errors.h" +#include "trace.h" +#include "vie_impl.h" +#include "vie_channel.h" +#include "vie_encoder.h" +#include "vie_channel_manager.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// GetInterface +// ---------------------------------------------------------------------------- + +ViEExternalCodec* ViEExternalCodec::GetInterface(VideoEngine* videoEngine) +{ +#ifdef WEBRTC_VIDEO_ENGINE_EXTERNAL_CODEC_API + if (videoEngine == NULL) + { + return NULL; + } + VideoEngineImpl* vieImpl = reinterpret_cast (videoEngine); + ViEExternalCodecImpl* vieExternalCodecImpl = vieImpl; + (*vieExternalCodecImpl)++; // Increase ref count + + return vieExternalCodecImpl; +#else + return NULL; +#endif +} + +// ---------------------------------------------------------------------------- +// Release +// +// Releases the interface, i.e. reduces the reference counter. The number of +// remaining references is returned, -1 if released too many times. +// ---------------------------------------------------------------------------- + +int ViEExternalCodecImpl::Release() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "ViEExternalCodec::Release()"); + (*this)--; // Decrease ref count + + WebRtc_Word32 refCount = GetCount(); + if (refCount < 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, + "ViEExternalCodec release too many times"); + SetLastError(kViEAPIDoesNotExist); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId, + "ViEExternalCodec reference count: %d", refCount); + return refCount; +} + +// ---------------------------------------------------------------------------- +// RegisterExternalSendCodec +// ---------------------------------------------------------------------------- + +int ViEExternalCodecImpl::RegisterExternalSendCodec(const int videoChannel, + const unsigned char plType, + VideoEncoder* encoder) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s channel %d plType %d encoder 0x%x", __FUNCTION__, + videoChannel, plType, encoder); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (!vieEncoder) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Invalid argument videoChannel %u. Does it exist?", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidArgument); + return -1; + } + if (!encoder) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Invalid argument Encoder 0x%x.", __FUNCTION__, encoder); + SetLastError(kViECodecInvalidArgument); + return -1; + } + + if (vieEncoder->RegisterExternalEncoder(encoder, plType) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; +} + +int ViEExternalCodecImpl::DeRegisterExternalSendCodec( + const int videoChannel, const unsigned char plType) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s channel %d plType %d", __FUNCTION__, videoChannel, plType); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (!vieEncoder) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Invalid argument videoChannel %u. Does it exist?", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidArgument); + return -1; + } + + if (vieEncoder->DeRegisterExternalEncoder(plType) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; + +} + +int ViEExternalCodecImpl::RegisterExternalReceiveCodec( + const int videoChannel, const unsigned int plType, VideoDecoder* decoder, + bool decoderRender /*= false*/, int renderDelay /*= 0*/) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s channel %d plType %d decoder 0x%x, decoderRender %d, " + "renderDelay %d", __FUNCTION__, videoChannel, plType, decoder, + decoderRender, renderDelay); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (!vieChannel) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Invalid argument videoChannel %u. Does it exist?", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidArgument); + return -1; + } + if (!decoder) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Invalid argument decoder 0x%x.", __FUNCTION__, decoder); + SetLastError(kViECodecInvalidArgument); + return -1; + } + + if (vieChannel->RegisterExternalDecoder(plType, decoder, decoderRender, + renderDelay) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; +} + +int ViEExternalCodecImpl::DeRegisterExternalReceiveCodec( + const int videoChannel, const unsigned char plType) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s channel %d plType %u", __FUNCTION__, videoChannel, plType); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (!vieChannel) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Invalid argument videoChannel %u. Does it exist?", + __FUNCTION__, videoChannel); + SetLastError(kViECodecInvalidArgument); + return -1; + } + if (vieChannel->DeRegisterExternalDecoder(plType) != 0) + { + SetLastError(kViECodecUnknownError); + return -1; + } + return 0; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_external_codec_impl.h b/video_engine/main/source/vie_external_codec_impl.h new file mode 100644 index 0000000000..101585c2bf --- /dev/null +++ b/video_engine/main/source/vie_external_codec_impl.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_external_codec_impl.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_EXTERNAL_CODEC_IMPL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_EXTERNAL_CODEC_IMPL_H_ + +#include "vie_external_codec.h" +#include "vie_ref_count.h" +#include "vie_shared_data.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// ViEExternalCodec +// ---------------------------------------------------------------------------- + +class ViEExternalCodecImpl : public virtual ViESharedData, + public ViEExternalCodec, + public ViERefCount +{ +public: + + virtual int Release(); + + virtual int RegisterExternalSendCodec(const int videoChannel, + const unsigned char plType, + VideoEncoder* encoder); + + virtual int DeRegisterExternalSendCodec(const int videoChannel, + const unsigned char plType); + + virtual int RegisterExternalReceiveCodec(const int videoChannel, + const unsigned int plType, + VideoDecoder* decoder, + bool decoderRender = false, + int renderDelay = 0); + + virtual int DeRegisterExternalReceiveCodec(const int videoChannel, + const unsigned char plType); +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_EXTERNAL_CODEC_IMPL_H_ diff --git a/video_engine/main/source/vie_file_image.cc b/video_engine/main/source/vie_file_image.cc new file mode 100644 index 0000000000..1ddb70aa65 --- /dev/null +++ b/video_engine/main/source/vie_file_image.cc @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_file_image.cc + */ + +#include +#include "vie_file_image.h" +#include "jpeg.h" +#include "trace.h" + +namespace webrtc { + +int ViEFileImage::ConvertJPEGToVideoFrame(int engineId, + const char* fileNameUTF8, + VideoFrame& videoFrame) +{ + // read jpeg file into temporary buffer + WebRtc_UWord8* imageBuffer; + WebRtc_UWord32 imageBufferSize; + FILE* imageFile = fopen(fileNameUTF8, "rb"); + if (NULL == imageFile) + { + // error reading file + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, engineId, + "%s could not open file %s", __FUNCTION__, fileNameUTF8); + return -1; + } + fseek(imageFile, 0, SEEK_END); + imageBufferSize = ftell(imageFile); + fseek(imageFile, 0, SEEK_SET); + imageBuffer = new WebRtc_UWord8[imageBufferSize + 1]; + if (imageBufferSize != fread(imageBuffer, sizeof(WebRtc_UWord8), + imageBufferSize, imageFile)) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, engineId, + "%s could not read file %s", __FUNCTION__, fileNameUTF8); + delete imageBuffer; + return -1; + } + fclose(imageFile); + + // if this is a jpeg file, decode it + JpegDecoder decoder; + + int ret = 0; + WebRtc_UWord8* imageDecodedBuffer = NULL; + WebRtc_UWord32 imageWidth, imageHeight = 0; + ret = decoder.Decode(imageBuffer, imageBufferSize, imageDecodedBuffer, + imageWidth, imageHeight); + + // done with this. + delete imageBuffer; + + if (-1 == ret) + { + // error decoding the file + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, engineId, + "%s could decode file %s from jpeg format", __FUNCTION__, + fileNameUTF8); + return -1; + } else if (-3 == ret) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, engineId, + "%s could not convert jpeg's data to i420 format", + __FUNCTION__, fileNameUTF8); + } + + WebRtc_UWord32 imageLength = (WebRtc_UWord32)(imageWidth * imageHeight + * 1.5); + if (-1 == videoFrame.Swap(imageDecodedBuffer, imageLength, imageLength)) + { + WEBRTC_TRACE( + webrtc::kTraceDebug, + webrtc::kTraceVideo, + engineId, + "%s could not copy frame imageDecodedBuffer to frame videoFrame ", + __FUNCTION__, fileNameUTF8); + return -1; + } + videoFrame.SetWidth(imageWidth); + videoFrame.SetHeight(imageHeight); + return 0; +} + +int ViEFileImage::ConvertPictureToVideoFrame(int engineId, + const ViEPicture& picture, + VideoFrame& videoFrame) +{ + WebRtc_UWord32 pictureLength = (WebRtc_UWord32)(picture.width + * picture.height * 1.5); + videoFrame.CopyFrame(pictureLength, picture.data); + videoFrame.SetWidth(picture.width); + videoFrame.SetHeight(picture.height); + videoFrame.SetLength(pictureLength); + + return 0; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_file_image.h b/video_engine/main/source/vie_file_image.h new file mode 100644 index 0000000000..be049d754d --- /dev/null +++ b/video_engine/main/source/vie_file_image.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_file_image.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_IMAGE_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_IMAGE_H_ + +#include "typedefs.h" +#include "vie_file.h" +#include "module_common_types.h" +namespace webrtc { +class ViEFileImage +{ +public: + static int ConvertJPEGToVideoFrame(int engineId, + const char* fileNameUTF8, + VideoFrame& videoFrame); + static int ConvertPictureToVideoFrame(int engineId, + const ViEPicture& picture, + VideoFrame& videoFrame); +}; +} // namespace webrtc + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_IMAGE_H_ diff --git a/video_engine/main/source/vie_file_impl.cc b/video_engine/main/source/vie_file_impl.cc new file mode 100644 index 0000000000..7488d06931 --- /dev/null +++ b/video_engine/main/source/vie_file_impl.cc @@ -0,0 +1,1285 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_file_impl.cc + */ + +#include "vie_file_impl.h" + +// Defines +#include "vie_defines.h" + +// Includes +#include "condition_variable_wrapper.h" +#include "critical_section_wrapper.h" +#include "jpeg.h" +#include "trace.h" +#include "vie_capturer.h" +#include "vie_channel.h" +#include "vie_channel_manager.h" +#include "vie_encoder.h" +#include "vie_errors.h" +#include "vie_file_image.h" +#include "vie_file_player.h" +#include "vie_file_recorder.h" +#include "vie_impl.h" +#include "vie_input_manager.h" +#include "vie_render_manager.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// GetInterface +// ---------------------------------------------------------------------------- + +ViEFile* ViEFile::GetInterface(VideoEngine* videoEngine) +{ +#ifdef WEBRTC_VIDEO_ENGINE_FILE_API + if (videoEngine == NULL) + { + return NULL; + } + VideoEngineImpl* vieImpl = reinterpret_cast (videoEngine); + ViEFileImpl* vieFileImpl = vieImpl; + (*vieFileImpl)++; // Increase ref count + + return vieFileImpl; +#else + return NULL; +#endif +} + +// ---------------------------------------------------------------------------- +// Release +// +// Releases the interface, i.e. reduces the reference counter. The number of +// remaining references is returned, -1 if released too many times. +// ---------------------------------------------------------------------------- + +int ViEFileImpl::Release() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "ViEFile::Release()"); + (*this)--; // Decrease ref count + + WebRtc_Word32 refCount = GetCount(); + if (refCount < 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, + "ViEFile release too many times"); + SetLastError(kViEAPIDoesNotExist); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId, + "ViEFile reference count: %d", refCount); + return refCount; +} + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViEFileImpl::ViEFileImpl() + +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViEFileImpl::ViEFileImpl() Ctor"); + +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViEFileImpl::~ViEFileImpl() +{ + + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViEFileImpl::~ViEFileImpl() Dtor"); +} + +// ---------------------------------------------------------------------------- +// StartPlayFile +// ---------------------------------------------------------------------------- +// Play file +int ViEFileImpl::StartPlayFile(const char* fileNameUTF8, int& fileId, + const bool loop /*= false*/, + const webrtc::FileFormats fileFormat + /*= webrtc::kFileFormatAviFile*/) +{ + + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", + __FUNCTION__); + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + VoiceEngine* voice = _channelManager.GetVoiceEngine(); + const WebRtc_Word32 result = _inputManager.CreateFilePlayer(fileNameUTF8, + loop, + fileFormat, + voice, fileId); + if (result != 0) + { + SetLastError(result); + return -1; + } + return 0; +} + +int ViEFileImpl::StopPlayFile(const int fileId) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(fileId: %d)", __FUNCTION__, fileId); + + { + ViEInputManagerScoped is(_inputManager); + ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId); + if (ptrViEFilePlayer == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: File with id %d is not playing.", __FUNCTION__, + fileId); + SetLastError(kViEFileNotPlaying); + return -1; + } + } + + // Destroy the capture device + return _inputManager.DestroyFilePlayer(fileId); + +} + +int ViEFileImpl::RegisterObserver(int fileId, ViEFileObserver& observer) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(fileId: %d)", __FUNCTION__, fileId); + + ViEInputManagerScoped is(_inputManager); + ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId); + if (ptrViEFilePlayer == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: File with id %d is not playing.", __FUNCTION__, + fileId); + SetLastError(kViEFileNotPlaying); + return -1; + } + if (ptrViEFilePlayer->IsObserverRegistered()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, fileId), + "%s: Observer already registered", __FUNCTION__); + SetLastError(kViEFileObserverAlreadyRegistered); + return -1; + } + if (ptrViEFilePlayer->RegisterObserver(observer) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, fileId), + "%s: Failed to register observer", __FUNCTION__, fileId); + SetLastError(kViEFileUnknownError); + return -1; + } + return 0; + +} + +int ViEFileImpl::DeregisterObserver(int fileId, ViEFileObserver& observer) +{ + + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(fileId: %d)", __FUNCTION__, fileId); + + ViEInputManagerScoped is(_inputManager); + ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId); + if (ptrViEFilePlayer == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: File with id %d is not playing.", __FUNCTION__, + fileId); + SetLastError(kViEFileNotPlaying); + return -1; + } + if (!ptrViEFilePlayer->IsObserverRegistered()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, fileId), "%s: No Observer registered", + __FUNCTION__); + SetLastError(kViEFileObserverNotRegistered); + return -1; + } + if (ptrViEFilePlayer->DeRegisterObserver() != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, fileId), + "%s: Failed to deregister observer", __FUNCTION__, fileId); + SetLastError(kViEFileUnknownError); + return -1; + } + return 0; + +} + +int ViEFileImpl::SendFileOnChannel(const int fileId, const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(fileId: %d)", __FUNCTION__, fileId); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel); + if (ptrViEEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViEFileInvalidChannelId); + return -1; + } + + ViEInputManagerScoped is(_inputManager); + if (is.FrameProvider(ptrViEEncoder) != NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d already connected to a capture device or " + "file.", __FUNCTION__, videoChannel); + SetLastError(kViEFileInputAlreadyConnected); + return -1; + } + + ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId); + if (ptrViEFilePlayer == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: File with id %d is not playing.", __FUNCTION__, + fileId); + SetLastError(kViEFileNotPlaying); + return -1; + } + + if (ptrViEFilePlayer->RegisterFrameCallback(videoChannel, ptrViEEncoder) + != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Failed to register frame callback.", __FUNCTION__, + fileId); + SetLastError(kViEFileUnknownError); + return -1; + } + return 0; +} + +int ViEFileImpl::StopSendFileOnChannel(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(videoChannel: %d)", __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel); + if (ptrViEEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViEFileInvalidChannelId); + return -1; + } + + ViEInputManagerScoped is(_inputManager); + ViEFrameProviderBase* frameProvider = is.FrameProvider(ptrViEEncoder); + if (frameProvider == NULL + || frameProvider->Id() < kViEFileIdBase + || frameProvider->Id() > kViEFileIdMax) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: No file connected to Channel %d", __FUNCTION__, + videoChannel); + SetLastError(kViEFileNotConnected); + return -1; + } + if (frameProvider->DeregisterFrameCallback(ptrViEEncoder) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Failed to deregister file from channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViEFileUnknownError); + } + return 0; + +} + +int ViEFileImpl::StartPlayFileAsMicrophone(const int fileId, + const int audioChannel, + bool mixMicrophone /*= false*/, + float volumeScaling /*= 1*/) +{ + ViEInputManagerScoped is(_inputManager); + + ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId); + if (ptrViEFilePlayer == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: File with id %d is not playing.", __FUNCTION__, + fileId); + SetLastError(kViEFileNotPlaying); + return -1; + } + if (ptrViEFilePlayer->SendAudioOnChannel(audioChannel, mixMicrophone, + volumeScaling) != 0) + { + SetLastError(kViEFileVoEFailure); + return -1; + } + return 0; + +} + +int ViEFileImpl::StopPlayFileAsMicrophone(const int fileId, + const int audioChannel) +{ + ViEInputManagerScoped is(_inputManager); + + ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId); + if (ptrViEFilePlayer == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: File with id %d is not playing.", __FUNCTION__, + fileId); + SetLastError(kViEFileNotPlaying); + return -1; + } + + if (ptrViEFilePlayer->StopSendAudioOnChannel(audioChannel) != 0) + { + SetLastError(kViEFileVoEFailure); + return -1; + } + return 0; +} + +int ViEFileImpl::StartPlayAudioLocally(const int fileId, + const int audioChannel, + float volumeScaling /*=1*/) +{ + ViEInputManagerScoped is(_inputManager); + + ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId); + if (ptrViEFilePlayer == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: File with id %d is not playing.", __FUNCTION__, + fileId); + SetLastError(kViEFileNotPlaying); + return -1; + } + if (ptrViEFilePlayer->PlayAudioLocally(audioChannel, volumeScaling) != 0) + { + SetLastError(kViEFileVoEFailure); + return -1; + } + return 0; +} + +int ViEFileImpl::StopPlayAudioLocally(const int fileId, const int audioChannel) +{ + ViEInputManagerScoped is(_inputManager); + + ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId); + if (ptrViEFilePlayer == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: File with id %d is not playing.", __FUNCTION__, + fileId); + SetLastError(kViEFileNotPlaying); + return -1; + } + if (ptrViEFilePlayer->StopPlayAudioLocally(audioChannel) != 0) + { + SetLastError(kViEFileVoEFailure); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// StartRecordOutgoingVideo +// ---------------------------------------------------------------------------- +int ViEFileImpl::StartRecordOutgoingVideo(const int videoChannel, + const char* fileNameUTF8, + AudioSource audioSource, + const webrtc::CodecInst& audioCodec, + const VideoCodec& videoCodec, + const webrtc::FileFormats fileFormat + /*= webrtc::kFileFormatAviFile*/) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s videoChannel: %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel); + if (ptrViEEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViEFileInvalidChannelId); + return -1; + } + ViEFileRecorder& fileRecorder = ptrViEEncoder->GetOutgoingFileRecorder(); + if (fileRecorder.RecordingStarted()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Already recording outgoing video on channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViEFileAlreadyRecording); + return -1; + } + + WebRtc_Word32 veChannelId = -1; + VoiceEngine* vePtr = NULL; + if (audioSource != NO_AUDIO) + { + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + veChannelId = ptrViEChannel->VoiceChannel(); + vePtr = _channelManager.GetVoiceEngine(); + + if (!vePtr) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Can't access voice engine. Have SetVoiceEngine " + "been called?", __FUNCTION__); + SetLastError(kViEFileVoENotSet); + return -1; + } + } + if (fileRecorder.StartRecording(fileNameUTF8, videoCodec, audioSource, + veChannelId, audioCodec, vePtr, + fileFormat) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Failed to start recording. Check arguments.", + __FUNCTION__); + SetLastError(kViEFileUnknownError); + return -1; + } + + return 0; +} + +int ViEFileImpl::StopRecordOutgoingVideo(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s videoChannel: %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel); + if (ptrViEEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViEFileInvalidChannelId); + return -1; + } + ViEFileRecorder& fileRecorder = ptrViEEncoder->GetOutgoingFileRecorder(); + if (!fileRecorder.RecordingStarted()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d is not recording.", __FUNCTION__, + videoChannel); + SetLastError(kViEFileNotRecording); + return -1; + } + if (fileRecorder.StopRecording() != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Failed to stop recording of channel %d.", + __FUNCTION__, videoChannel); + SetLastError(kViEFileUnknownError); + return -1; + } + return 0; + +} +int ViEFileImpl::StopRecordIncomingVideo(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s videoChannel: %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViEFileInvalidChannelId); + return -1; + } + ViEFileRecorder& fileRecorder = ptrViEChannel->GetIncomingFileRecorder(); + if (!fileRecorder.RecordingStarted()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d is not recording.", __FUNCTION__, + videoChannel); + SetLastError(kViEFileNotRecording); + ptrViEChannel->ReleaseIncomingFileRecorder(); + + return -1; + } + if (fileRecorder.StopRecording() != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Failed to stop recording of channel %d.", + __FUNCTION__, videoChannel); + SetLastError(kViEFileUnknownError); + ptrViEChannel->ReleaseIncomingFileRecorder(); + return -1; + } + // Let the channel know we are no longer recording + ptrViEChannel->ReleaseIncomingFileRecorder(); + return 0; + +} + +int ViEFileImpl::StartRecordIncomingVideo(const int videoChannel, + const char* fileNameUTF8, + AudioSource audioSource, + const webrtc::CodecInst& audioCodec, + const VideoCodec& videoCodec, + const webrtc::FileFormats fileFormat + /*= webrtc::kFileFormatAviFile*/) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s videoChannel: %d)", + __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViEFileInvalidChannelId); + return -1; + } + ViEFileRecorder& fileRecorder = ptrViEChannel->GetIncomingFileRecorder(); + if (fileRecorder.RecordingStarted()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Already recording outgoing video on channel %d", + __FUNCTION__, videoChannel); + SetLastError(kViEFileAlreadyRecording); + return -1; + } + + WebRtc_Word32 veChannelId = -1; + VoiceEngine* vePtr = NULL; + if (audioSource != NO_AUDIO) + { + veChannelId = ptrViEChannel->VoiceChannel(); + vePtr = _channelManager.GetVoiceEngine(); + + if (!vePtr) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Can't access voice engine. Have SetVoiceEngine " + "been called?", __FUNCTION__); + SetLastError(kViEFileVoENotSet); + return -1; + } + } + if (fileRecorder.StartRecording(fileNameUTF8, videoCodec, audioSource, + veChannelId, audioCodec, vePtr, fileFormat) + != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Failed to start recording. Check arguments.", + __FUNCTION__); + SetLastError(kViEFileUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// File information +// ============================================================================ + +// ---------------------------------------------------------------------------- +// GetFileInformation +// +// +// ---------------------------------------------------------------------------- + +int ViEFileImpl::GetFileInformation(const char* fileName, + VideoCodec& videoCodec, + webrtc::CodecInst& audioCodec, + const webrtc::FileFormats fileFormat + /*= webrtc::kFileFormatAviFile*/) +{ + return ViEFilePlayer::GetFileInformation( + _instanceId, (WebRtc_Word8*) fileName, + videoCodec, audioCodec, fileFormat); +} + +// ============================================================================ +// Snapshot +// ============================================================================ +// ---------------------------------------------------------------------------- + +int ViEFileImpl::GetRenderSnapshot(const int videoChannel, + const char* fileNameUTF8) +{ + // gain access to the renderer for the specified channel and get it's + // current frame + ViERenderManagerScoped rs(_renderManager); + ViERenderer* ptrRender = rs.Renderer(videoChannel); + if (!ptrRender) + { + return -1; + } + + VideoFrame videoFrame; + if (-1 == ptrRender->GetLastRenderedFrame(videoChannel, videoFrame)) + { + return -1; + } + + const int JPEG_FORMAT = 0; + int format = JPEG_FORMAT; + + switch (format) + { + case JPEG_FORMAT: + { + // *** JPEGEncoder writes the jpeg file for you (no control + // over it) and does not return you the buffer + // *** Thusly, we are not going to be writing to the disk here + + JpegEncoder jpegEncoder; + + if (-1 == jpegEncoder.SetFileName(fileNameUTF8)) + { + // could not set filename for whatever reason + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + "\tCould not open output file '%s' for writing!", + fileNameUTF8); + return -1; + } + + if (-1 == jpegEncoder.Encode(videoFrame.Buffer(), + videoFrame.Length(), + videoFrame.Width(), + videoFrame.Height())) + { + // could not encode i420->jpeg + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + "\tCould not encode i420 -> jpeg file '%s' for " + "writing!", fileNameUTF8); + return -1; + } + + break; + } + default: + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceFile, _instanceId, + "\tUnsupported file format for %s", __FUNCTION__); + return -1; + break; + } + } + return 0; +} + +// ---------------------------------------------------------------------------- +// +// GetRenderSnapshot +// ---------------------------------------------------------------------------- + +int ViEFileImpl::GetRenderSnapshot(const int videoChannel, ViEPicture& picture) +{ + + // gain access to the renderer for the specified channel and get it's + // current frame + ViERenderManagerScoped rs(_renderManager); + ViERenderer* ptrRender = rs.Renderer(videoChannel); + if (!ptrRender) + { + return -1; + } + + VideoFrame videoFrame; + if (-1 == ptrRender->GetLastRenderedFrame(videoChannel, videoFrame)) + { + return -1; + } + + // copy from VideoFrame class to ViEPicture struct + int bufferLength = (int) (videoFrame.Width() * videoFrame.Height() * 1.5); + picture.data + = (WebRtc_UWord8*) malloc(bufferLength * sizeof(WebRtc_UWord8)); + memcpy(picture.data, videoFrame.Buffer(), bufferLength); + picture.size = bufferLength; + picture.width = videoFrame.Width(); + picture.height = videoFrame.Height(); + picture.type = kVideoI420; + + return 0; +} + +// ---------------------------------------------------------------------------- +// +// +// GetCaptureDeviceSnapshot +// ---------------------------------------------------------------------------- + +int ViEFileImpl::GetCaptureDeviceSnapshot(const int captureId, + const char* fileNameUTF8) +{ + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrCapture = is.Capture(captureId); + if (!ptrCapture) + { + return -1; + } + + VideoFrame videoFrame; + if (GetNextCapturedFrame(captureId, videoFrame) == -1) + { + // Failed to get a snapshot... + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + "Could not gain acces to capture device %d video frame " + "%s:%d", captureId, __FUNCTION__); + return -1; + } + + const int JPEG_FORMAT = 0; + int format = JPEG_FORMAT; + + switch (format) + { + case JPEG_FORMAT: + { + // *** JPEGEncoder writes the jpeg file for you (no control + // over it) and does not return you the buffer + // *** Thusly, we are not going to be writing to the disk here + + JpegEncoder jpegEncoder; + + if (-1 == jpegEncoder.SetFileName(fileNameUTF8)) + { + // could not set filename for whatever reason + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + "\tCould not open output file '%s' for writing!", + fileNameUTF8); + return -1; + } + + if (-1 == jpegEncoder.Encode(videoFrame.Buffer(), + videoFrame.Length(), + videoFrame.Width(), + videoFrame.Height())) + { + // could not encode i420->jpeg + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + "\tCould not encode i420 -> jpeg file '%s' for " + "writing!", fileNameUTF8); + return -1; + } + + break; + } + default: + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceFile, _instanceId, + "\tUnsupported file format for %s", __FUNCTION__); + return -1; + break; + } + } + return 0; +} + +// ---------------------------------------------------------------------------- +// +// +// GetCaptureDeviceSnapshot +// ---------------------------------------------------------------------------- + +int ViEFileImpl::GetCaptureDeviceSnapshot(const int captureId, + ViEPicture& picture) +{ + VideoFrame videoFrame; + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrCapture = is.Capture(captureId); + if (!ptrCapture) + { + return -1; + } + + if (GetNextCapturedFrame(captureId, videoFrame) == -1) + { + // Failed to get a snapshot... + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId, + "Could not gain acces to capture device %d video frame " + "%s:%d", captureId, __FUNCTION__); + return -1; + } + + // copy from VideoFrame class to ViEPicture struct + int bufferLength = (int) (videoFrame.Width() * videoFrame.Height() * 1.5); + picture.data + = (WebRtc_UWord8*) malloc(bufferLength * sizeof(WebRtc_UWord8)); + memcpy(picture.data, videoFrame.Buffer(), bufferLength); + picture.size = bufferLength; + picture.width = videoFrame.Width(); + picture.height = videoFrame.Height(); + picture.type = kVideoI420; + + return 0; +} + +// ---------------------------------------------------------------------------- +// +// +// FreePicture +// ---------------------------------------------------------------------------- + +int ViEFileImpl::FreePicture(ViEPicture& picture) +{ + if (picture.data) + free(picture.data); + + picture.data = NULL; + picture.size = 0; + picture.width = 0; + picture.height = 0; + picture.type = kVideoUnknown; + + return 0; +} + +// ============================================================================ +// Capture device images +// ============================================================================ + +// ---------------------------------------------------------------------------- +// +// +// SetCaptureDeviceImage +// ---------------------------------------------------------------------------- + +int ViEFileImpl::SetCaptureDeviceImage(const int captureId, + const char* fileNameUTF8) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "%s(captureId: %d)", __FUNCTION__, captureId); + + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrCapture = is.Capture(captureId); + if (!ptrCapture) + { + SetLastError(kViEFileInvalidCaptureId); + return -1; + } + + VideoFrame captureImage; + if (ViEFileImage::ConvertJPEGToVideoFrame( + ViEId(_instanceId, captureId), fileNameUTF8, captureImage) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, captureId), + "%s(captureId: %d) Failed to open file.", __FUNCTION__, + captureId); + SetLastError(kViEFileInvalidFile); + return -1; + } + if (ptrCapture->SetCaptureDeviceImage(captureImage)) + { + SetLastError(kViEFileSetCaptureImageError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// +// +// SetCaptureDeviceImage +// ---------------------------------------------------------------------------- + +int ViEFileImpl::SetCaptureDeviceImage(const int captureId, + const ViEPicture& picture) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "%s(captureId: %d)", __FUNCTION__, captureId); + + if (picture.type != kVideoI420) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, captureId), + "%s(captureId: %d) Not a valid picture type.", + __FUNCTION__, captureId); + SetLastError(kViEFileInvalidArgument); + return -1; + } + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrCapture = is.Capture(captureId); + if (!ptrCapture) + { + SetLastError(kViEFileSetCaptureImageError); + return -1; + } + + VideoFrame captureImage; + if (ViEFileImage::ConvertPictureToVideoFrame( + ViEId(_instanceId,captureId), picture, captureImage) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, captureId), + "%s(captureId: %d) Failed to use picture.", __FUNCTION__, + captureId); + SetLastError(kViEFileInvalidFile); + return -1; + } + if (ptrCapture->SetCaptureDeviceImage(captureImage)) + { + SetLastError(kViEFileInvalidCapture); + return -1; + } + return 0; +} + +// ============================================================================ +// Render images +// ============================================================================ + +// ---------------------------------------------------------------------------- +// +// +// SetRenderStartImage +// ---------------------------------------------------------------------------- + +int ViEFileImpl::SetRenderStartImage(const int videoChannel, + const char* fileNameUTF8) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)", + __FUNCTION__, videoChannel); + + ViERenderManagerScoped rs(_renderManager); + ViERenderer* ptrRender = rs.Renderer(videoChannel); + if (!ptrRender) + { + SetLastError(kViEFileInvalidRenderId); + return -1; + } + + VideoFrame startImage; + if (ViEFileImage::ConvertJPEGToVideoFrame( + ViEId(_instanceId, videoChannel), fileNameUTF8, startImage) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d) Failed to open file.", __FUNCTION__, + videoChannel); + SetLastError(kViEFileInvalidFile); + return -1; + } + if (ptrRender->SetRenderStartImage(startImage) != 0) + { + SetLastError(kViEFileSetStartImageError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// +// +// SetRenderStartImage +// ---------------------------------------------------------------------------- + +int ViEFileImpl::SetRenderStartImage(const int videoChannel, + const ViEPicture& picture) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)", + __FUNCTION__, videoChannel); + + if (picture.type != kVideoI420) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d) Not a valid picture type.", + __FUNCTION__, videoChannel); + SetLastError(kViEFileInvalidArgument); + return -1; + } + + ViERenderManagerScoped rs(_renderManager); + ViERenderer* ptrRender = rs.Renderer(videoChannel); + if (!ptrRender) + { + SetLastError(kViEFileInvalidRenderId); + return -1; + } + + VideoFrame startImage; + if (ViEFileImage::ConvertPictureToVideoFrame( + ViEId(_instanceId, videoChannel), picture, startImage) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d) Failed to use picture.", + __FUNCTION__, videoChannel); + SetLastError(kViEFileInvalidCapture); + return -1; + } + if (ptrRender->SetRenderStartImage(startImage) != 0) + { + SetLastError(kViEFileSetStartImageError); + return -1; + } + return 0; +} + +// ============================================================================ +// Timeout image +// ============================================================================ + +// ---------------------------------------------------------------------------- +// +// +// SetRenderTimeoutImage +// ---------------------------------------------------------------------------- + +int ViEFileImpl::SetRenderTimeoutImage(const int videoChannel, + const char* fileNameUTF8, + const unsigned int timeoutMs) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)", + __FUNCTION__, videoChannel); + + ViERenderManagerScoped rs(_renderManager); + ViERenderer* ptrRender = rs.Renderer(videoChannel); + if (!ptrRender) + { + SetLastError(kViEFileInvalidRenderId); + return -1; + } + VideoFrame timeoutImage; + if (ViEFileImage::ConvertJPEGToVideoFrame( + ViEId(_instanceId,videoChannel), fileNameUTF8, timeoutImage) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d) Failed to open file.", __FUNCTION__, + videoChannel); + SetLastError(kViEFileInvalidFile); + return -1; + } + WebRtc_Word32 timeoutTime = timeoutMs; + if (timeoutMs < kViEMinRenderTimeoutTimeMs) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d) Invalid timeoutMs, using %d.", + __FUNCTION__, videoChannel, kViEMinRenderTimeoutTimeMs); + timeoutTime = kViEMinRenderTimeoutTimeMs; + } + if (timeoutMs > kViEMaxRenderTimeoutTimeMs) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d) Invalid timeoutMs, using %d.", + __FUNCTION__, videoChannel, kViEMaxRenderTimeoutTimeMs); + timeoutTime = kViEMaxRenderTimeoutTimeMs; + } + if (ptrRender->SetTimeoutImage(timeoutImage, timeoutTime) != 0) + { + SetLastError(kViEFileSetRenderTimeoutError); + return -1; + } + return 0; +} + +int ViEFileImpl::SetRenderTimeoutImage(const int videoChannel, + const ViEPicture& picture, + const unsigned int timeoutMs) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)", + __FUNCTION__, videoChannel); + + if (picture.type != kVideoI420) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d) Not a valid picture type.", + __FUNCTION__, videoChannel); + SetLastError(kViEFileInvalidArgument); + return -1; + } + + ViERenderManagerScoped rs(_renderManager); + ViERenderer* ptrRender = rs.Renderer(videoChannel); + if (!ptrRender) + { + SetLastError(kViEFileSetRenderTimeoutError); + return -1; + } + VideoFrame timeoutImage; + if (ViEFileImage::ConvertPictureToVideoFrame( + ViEId(_instanceId, videoChannel), picture, timeoutImage) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d) Failed to use picture.", + __FUNCTION__, videoChannel); + SetLastError(kViEFileInvalidCapture); + return -1; + } + WebRtc_Word32 timeoutTime = timeoutMs; + if (timeoutMs < kViEMinRenderTimeoutTimeMs) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d) Invalid timeoutMs, using %d.", + __FUNCTION__, videoChannel, kViEMinRenderTimeoutTimeMs); + timeoutTime = kViEMinRenderTimeoutTimeMs; + } + if (timeoutMs > kViEMaxRenderTimeoutTimeMs) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(videoChannel: %d) Invalid timeoutMs, using %d.", + __FUNCTION__, videoChannel, kViEMaxRenderTimeoutTimeMs); + timeoutTime = kViEMaxRenderTimeoutTimeMs; + } + if (ptrRender->SetTimeoutImage(timeoutImage, timeoutTime) != 0) + { + SetLastError(kViEFileSetRenderTimeoutError); + return -1; + } + return 0; +} + +WebRtc_Word32 ViEFileImpl::GetNextCapturedFrame(WebRtc_Word32 captureId, + VideoFrame& videoFrame) +{ + ViEInputManagerScoped is(_inputManager); + ViECapturer* ptrCapture = is.Capture(captureId); + if (!ptrCapture) + { + return -1; + } + + ViECaptureSnapshot* snapShot = new ViECaptureSnapshot(); + ptrCapture->RegisterFrameCallback(-1, snapShot); + bool snapshotTaken = + snapShot->GetSnapshot(videoFrame, kViECaptureMaxSnapshotWaitTimeMs); + + // Check once again if it has been destroyed... + ptrCapture->DeregisterFrameCallback(snapShot); + delete snapShot; + snapShot = NULL; + + if (snapshotTaken) + { + return 0; + } + return -1; +} + +ViECaptureSnapshot::ViECaptureSnapshot() : + _crit(*CriticalSectionWrapper::CreateCriticalSection()), + _conditionVaraible(*ConditionVariableWrapper::CreateConditionVariable()), + _ptrVideoFrame(NULL) +{ +} + +ViECaptureSnapshot::~ViECaptureSnapshot() +{ + _crit.Enter(); + _crit.Leave(); + delete &_crit; + if (_ptrVideoFrame) + { + delete _ptrVideoFrame; + _ptrVideoFrame = NULL; + } +} + +bool ViECaptureSnapshot::GetSnapshot(VideoFrame& videoFrame, + unsigned int maxWaitTime) +{ + _crit.Enter(); + _ptrVideoFrame = new VideoFrame(); + if (_conditionVaraible.SleepCS(_crit, maxWaitTime)) + { + // Snapshot taken + videoFrame.SwapFrame(*_ptrVideoFrame); + delete _ptrVideoFrame; + _ptrVideoFrame = NULL; + _crit.Leave(); + return true; + } + return false; +} + +void ViECaptureSnapshot::DeliverFrame(int id, VideoFrame& videoFrame, + int numCSRCs, + const WebRtc_UWord32 CSRC[kRtpCsrcSize]) +{ + CriticalSectionScoped cs(_crit); + if (!_ptrVideoFrame) + { + return; + } + _ptrVideoFrame->SwapFrame(videoFrame); + _conditionVaraible.WakeAll(); + return; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_file_impl.h b/video_engine/main/source/vie_file_impl.h new file mode 100644 index 0000000000..6345499eff --- /dev/null +++ b/video_engine/main/source/vie_file_impl.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_file_impl.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_IMPL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_IMPL_H_ + +#include "typedefs.h" +#include "vie_defines.h" +#include "vie_file.h" +#include "vie_frame_provider_base.h" +#include "vie_ref_count.h" +#include "vie_shared_data.h" + +namespace webrtc +{ +class ConditionVariableWrapper; + +// ---------------------------------------------------------------------------- +// ViECaptureSnapshot +// ---------------------------------------------------------------------------- + +class ViECaptureSnapshot: public ViEFrameCallback +{ +public: + ViECaptureSnapshot(); + ~ViECaptureSnapshot(); + + bool GetSnapshot(VideoFrame& videoFrame, unsigned int maxWaitTime); + + // From ViEFrameCallback + virtual void DeliverFrame(int id, VideoFrame& videoFrame, int numCSRCs = 0, + const WebRtc_UWord32 CSRC[kRtpCsrcSize] = NULL); + + virtual void DelayChanged(int id, int frameDelay) {} + + virtual int GetPreferedFrameSettings(int &width, int &height, + int &frameRate) + { + return -1; + } + + virtual void ProviderDestroyed(int id) {} + +private: + CriticalSectionWrapper& _crit; + ConditionVariableWrapper& _conditionVaraible; + VideoFrame* _ptrVideoFrame; +}; + +// ---------------------------------------------------------------------------- +// VideoFileImpl +// ---------------------------------------------------------------------------- + +class ViEFileImpl: public virtual ViESharedData, + public ViEFile, + public ViERefCount + +{ +public: + virtual int Release(); + + // Play file + virtual int StartPlayFile(const char* fileNameUTF8, int& fileId, + const bool loop = false, + const webrtc::FileFormats fileFormat = + webrtc::kFileFormatAviFile); + + virtual int StopPlayFile(const int fileId); + + virtual int RegisterObserver(int fileId, ViEFileObserver& observer); + + virtual int DeregisterObserver(int fileId, ViEFileObserver& observer); + + virtual int SendFileOnChannel(const int fileId, const int videoChannel); + + virtual int StopSendFileOnChannel(const int videoChannel); + + virtual int StartPlayFileAsMicrophone(const int fileId, + const int audioChannel, + bool mixMicrophone = false, + float volumeScaling = 1); + + virtual int StopPlayFileAsMicrophone(const int fileId, + const int audioChannel); + + virtual int StartPlayAudioLocally(const int fileId, const int audioChannel, + float volumeScaling = 1); + + virtual int StopPlayAudioLocally(const int fileId, const int audioChannel); + + virtual int StartRecordOutgoingVideo(const int videoChannel, + const char* fileNameUTF8, + AudioSource audioSource, + const webrtc::CodecInst& audioCodec, + const VideoCodec& videoCodec, + const webrtc::FileFormats fileFormat = + webrtc::kFileFormatAviFile); + + virtual int StartRecordIncomingVideo(const int videoChannel, + const char* fileNameUTF8, + AudioSource audioSource, + const webrtc::CodecInst& audioCodec, + const VideoCodec& videoCodec, + const webrtc::FileFormats fileFormat = + webrtc::kFileFormatAviFile); + + virtual int StopRecordOutgoingVideo(const int videoChannel); + + virtual int StopRecordIncomingVideo(const int videoChannel); + + // File information + virtual int GetFileInformation(const char* fileName, + VideoCodec& videoCodec, + webrtc::CodecInst& audioCodec, + const webrtc::FileFormats fileFormat = + webrtc::kFileFormatAviFile); + + // Snapshot + virtual int GetRenderSnapshot(const int videoChannel, + const char* fileNameUTF8); + + virtual int GetRenderSnapshot(const int videoChannel, ViEPicture& picture); + + virtual int FreePicture(ViEPicture& picture); + + virtual int GetCaptureDeviceSnapshot(const int captureId, + const char* fileNameUTF8); + + virtual int GetCaptureDeviceSnapshot(const int captureId, + ViEPicture& picture); + + // Capture device images + virtual int SetCaptureDeviceImage(const int captureId, + const char* fileNameUTF8); + + virtual int SetCaptureDeviceImage(const int captureId, + const ViEPicture& picture); + // Render images + virtual int SetRenderStartImage(const int videoChannel, + const char* fileNameUTF8); + + virtual int SetRenderStartImage(const int videoChannel, + const ViEPicture& picture); + + // Timeout image + virtual int SetRenderTimeoutImage(const int videoChannel, + const char* fileNameUTF8, + const unsigned int timeoutMs); + + virtual int SetRenderTimeoutImage(const int videoChannel, + const ViEPicture& picture, + const unsigned int timeoutMs); + +protected: + ViEFileImpl(); + virtual ~ViEFileImpl(); + +private: + WebRtc_Word32 GetNextCapturedFrame(WebRtc_Word32 captureId, + VideoFrame& videoFrame); + +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_IMPL_H_ diff --git a/video_engine/main/source/vie_file_player.cc b/video_engine/main/source/vie_file_player.cc new file mode 100644 index 0000000000..b933dd8d8e --- /dev/null +++ b/video_engine/main/source/vie_file_player.cc @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_file_player.cc + * + */ + +#include "critical_section_wrapper.h" +#include "trace.h" +#include "vie_file_player.h" +#include "tick_util.h" +#include "thread_wrapper.h" +#include "event_wrapper.h" +#include "vie_input_manager.h" +namespace webrtc { +ViEFilePlayer* ViEFilePlayer::CreateViEFilePlayer(int fileId, + int engineId, + const char* fileNameUTF8, + const bool loop, + const webrtc::FileFormats fileFormat, + ViEInputManager& inputManager, + VoiceEngine* vePtr) +{ + ViEFilePlayer* self = new ViEFilePlayer(fileId, engineId, inputManager); + if (!self || self->Init(fileNameUTF8, loop, fileFormat, vePtr) != 0) + { + delete self; + self = NULL; + } + return self; +} + +ViEFilePlayer::ViEFilePlayer(int Id, int engineId, + ViEInputManager& inputManager) + : ViEFrameProviderBase(Id, engineId), _playBackStarted(false), + _inputManager(inputManager), _ptrFeedBackCritSect(NULL), + _ptrAudioCritSect(NULL), _filePlayer(NULL), _audioStream(false), + _videoClients(0), _audioClients(0), _localAudioChannel(-1), _observer(NULL), + _veFileInterface(NULL), _veVideoSync(NULL), _ptrDecodeThread(NULL), + _ptrDecodeEvent(NULL), _decodedAudioLength(0), _audioChannelBuffers(), + _decodedVideo() +{ +} + +ViEFilePlayer::~ViEFilePlayer() +{ + StopPlay(); + delete _ptrDecodeEvent; + delete _ptrAudioCritSect; + delete _ptrFeedBackCritSect; +} + +int ViEFilePlayer::Init(const char* fileNameUTF8, const bool loop, + const webrtc::FileFormats fileFormat, + VoiceEngine* vePtr) +{ + + _ptrFeedBackCritSect = CriticalSectionWrapper::CreateCriticalSection(); + if (!_ptrFeedBackCritSect) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "ViEFilePlayer::StartPlay() failed to allocate critsect"); + return -1; + } + + _ptrAudioCritSect = CriticalSectionWrapper::CreateCriticalSection(); + if (!_ptrAudioCritSect) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "ViEFilePlayer::StartPlay() failed to allocate critsect"); + return -1; + } + + _ptrDecodeEvent = EventWrapper::Create(); + if (!_ptrDecodeEvent) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "ViEFilePlayer::StartPlay() failed to allocate event"); + return -1; + + } + if (strlen(fileNameUTF8) > FileWrapper::kMaxFileNameSize) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "ViEFilePlayer::StartPlay() To long filename"); + return -1; + } + strncpy(_fileName, fileNameUTF8, strlen(fileNameUTF8) + 1); + + _filePlayer = FilePlayer::CreateFilePlayer(ViEId(_engineId, _id), + fileFormat); + if (!_filePlayer) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "ViEFilePlayer::StartPlay() failed to create file player"); + return -1; + } + if (_filePlayer->RegisterModuleFileCallback(this) == -1) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "ViEFilePlayer::StartPlay() failed to RegisterModuleFileCallback"); + _filePlayer = NULL; + return -1; + } + _ptrDecodeThread = ThreadWrapper::CreateThread(FilePlayDecodeThreadFunction, + this, kHighestPriority, + "ViEFilePlayThread"); + if (!_ptrDecodeThread) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "ViEFilePlayer::StartPlay() failed to start decode thread."); + _filePlayer = NULL; + return -1; + + } + + // Always try to open with Audio since we don't know on what channels the audio should be played on. + WebRtc_Word32 error = _filePlayer->StartPlayingVideoFile(_fileName, loop, + false); + if (error) // Failed to open the file with audio. Try without + { + error = _filePlayer->StartPlayingVideoFile(_fileName, loop, true); + _audioStream = false; + if (error) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "ViEFilePlayer::StartPlay() failed to Start play video file"); + return -1; + } + + } else + { + _audioStream = true; + } + + if (_audioStream) // The file contain an audiostream + { + if (vePtr) // && localAudioChannel!=-1) // VeInterface have been provided and we want to play audio on local channel. + { + _veFileInterface = VoEFile::GetInterface(vePtr); + if (!_veFileInterface) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _id), + "ViEFilePlayer::StartPlay() failed to get VEFile interface"); + return -1; + } + _veVideoSync = VoEVideoSync::GetInterface(vePtr); + if (!_veVideoSync) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _id), + "ViEFilePlayer::StartPlay() failed to get " + "VoEVideoSync interface"); + return -1; + } + } + } + + _ptrDecodeEvent->StartTimer(true, 10); // Read audio /(or just video) every 10ms. + + return 0; +} +/* + //Implements ViEFrameProviderBase + // Starts the decode thread when someone cares. + */ +int ViEFilePlayer::FrameCallbackChanged() +{ + if (ViEFrameProviderBase::NumberOfRegistersFrameCallbacks() > _videoClients) + { + if (!_playBackStarted) + { + _playBackStarted = true; + unsigned int threadId; + if (_ptrDecodeThread->Start(threadId)) + { + WEBRTC_TRACE( + webrtc::kTraceStateInfo, + webrtc::kTraceVideo, + ViEId(_engineId, _id), + "ViEFilePlayer::FrameCallbackChanged() Started filedecode thread %u", + threadId); + } else + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _id), + "ViEFilePlayer::FrameCallbackChanged() Failed to start file decode thread."); + } + } else if (!_filePlayer->IsPlayingFile()) + { + if (_filePlayer->StartPlayingVideoFile(_fileName, false, + !_audioStream) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _id), + "ViEFilePlayer::FrameCallbackChanged(), Failed to restart the file player."); + + } + + } + } + _videoClients = ViEFrameProviderBase::NumberOfRegistersFrameCallbacks(); + return 0; + +} + +// File play decode function. +bool ViEFilePlayer::FilePlayDecodeThreadFunction(void* obj) +{ + return static_cast (obj)->FilePlayDecodeProcess(); +} +bool ViEFilePlayer::FilePlayDecodeProcess() +{ + + if (_ptrDecodeEvent->Wait(kThreadWaitTimeMs) == kEventSignaled) + { + if (_audioStream && _audioClients == 0) // If there is audio but no one cares- read the audio self + { + Read(NULL, 0); + } + if (_filePlayer->TimeUntilNextVideoFrame() < 10) // Less than 10ms to next videoframe + { + if (_filePlayer->GetVideoFromFile(_decodedVideo) != 0) + { + } + } + if (_decodedVideo.Length() > 0) + { + + if (_localAudioChannel != -1 && _veVideoSync) // We are playing audio locally + { + int audioDelay = 0; + if (_veVideoSync->GetPlayoutBufferSize(audioDelay) == 0) + { + _decodedVideo.SetRenderTime(_decodedVideo.RenderTimeMs() + + audioDelay); + } + } + DeliverFrame(_decodedVideo); + _decodedVideo.SetLength(0); + } + + } + return true; +} + +int ViEFilePlayer::StopPlay() //Only called from destructor. +{ + + bool threadStoped = false; + if (_ptrDecodeThread) + { + _ptrDecodeThread->SetNotAlive(); + if (_ptrDecodeThread->Stop()) + { + + delete _ptrDecodeThread; + } else + { + assert(!"ViEFilePlayer::StopPlay() Failed to stop decode thread"); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "ViEFilePlayer::StartPlay() Failed to stop file decode thread."); + } + } + + _ptrDecodeThread = NULL; + if (_ptrDecodeEvent) + { + _ptrDecodeEvent->StopTimer(); + } + + StopPlayAudio(); + + if (_veFileInterface) + { + _veFileInterface->Release(); + _veFileInterface = NULL; + } + if (_veVideoSync) + { + _veVideoSync->Release(); + _veVideoSync = NULL; + } + + if (_filePlayer) + { + _filePlayer->StopPlayingFile(); + FilePlayer::DestroyFilePlayer(_filePlayer); + _filePlayer = NULL; + } + + return 0; +} +int ViEFilePlayer::StopPlayAudio() +{ + // Stop sending audio + while (MapItem* audioItem = _audioChannelsSending.First()) + { + StopSendAudioOnChannel(audioItem->GetId()); + } + + // Stop local audio playback + if (_localAudioChannel != -1) + { + StopPlayAudioLocally(_localAudioChannel); + } + _localAudioChannel = -1; + while (_audioChannelBuffers.PopFront() != -1); + while (_audioChannelsSending.Erase(_audioChannelsSending.First()) != -1); + _audioClients = 0; + return 0; +} + +// From webrtc::InStream +int ViEFilePlayer::Read(void *buf, int len) +{ + CriticalSectionScoped lock(*_ptrAudioCritSect); // Protect from simultaneouse reading from multiple channels + if (NeedsAudioFromFile(buf)) + { + if (_filePlayer->Get10msAudioFromFile(_decodedAudio, + _decodedAudioLength, 16000) != 0) // we will run the VE in 16KHz + { + // No data + _decodedAudioLength = 0; + return 0; + } + _decodedAudioLength *= 2; // 2 bytes per sample + if (buf != 0) + { + _audioChannelBuffers.PushBack(buf); + } + } else + { + // No need for new audiobuffer from file. Ie the buffer read from file has not been played on this channel. + } + if (buf) + { + memcpy(buf, _decodedAudio, _decodedAudioLength); + } + return _decodedAudioLength; + +} +bool ViEFilePlayer::NeedsAudioFromFile(void* buf) +{ + bool needsNewAudio = false; + if (_audioChannelBuffers.GetSize() == 0) + { + return true; + } + + //Check if we the buf already have read the current audio. + for (ListItem* item = _audioChannelBuffers.First(); item != NULL; item + = _audioChannelBuffers.Next(item)) + { + if (item->GetItem() == buf) + { + needsNewAudio = true; + _audioChannelBuffers.Erase(item); + break; + } + } + return needsNewAudio; +} + +// From FileCallback +void ViEFilePlayer::PlayFileEnded(const WebRtc_Word32 id) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, id), + "%s: fileId %d", __FUNCTION__, _id); + + _filePlayer->StopPlayingFile(); + + CriticalSectionScoped lock(*_ptrFeedBackCritSect); + if (_observer) + { + _observer->PlayFileEnded(_id); + } +} + +bool ViEFilePlayer::IsObserverRegistered() +{ + CriticalSectionScoped lock(*_ptrFeedBackCritSect); + return _observer != NULL; + +} +int ViEFilePlayer::RegisterObserver(ViEFileObserver& observer) +{ + CriticalSectionScoped lock(*_ptrFeedBackCritSect); + if (_observer) + return -1; + _observer = &observer; + return 0; +} +int ViEFilePlayer::DeRegisterObserver() +{ + CriticalSectionScoped lock(*_ptrFeedBackCritSect); + _observer = NULL; + return 0; +} + +// ---------------------------------------------------------------------------- +// SendAudioOnChannel +// Order the voice engine to send the audio on a channel +// ---------------------------------------------------------------------------- +int ViEFilePlayer::SendAudioOnChannel(const int audioChannel, + bool mixMicrophone, float volumeScaling) +{ + + if (!_veFileInterface) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s No VEFile interface.", __FUNCTION__); + return -1; + } + if (_veFileInterface->StartPlayingFileAsMicrophone(audioChannel, + this, + mixMicrophone, + kFileFormatPcm16kHzFile, + volumeScaling) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "ViEFilePlayer::SendAudioOnChannel() VE_StartPlayingFileAsMicrophone failed. audioChannel %d, mixMicrophone %d, volumeScaling %.2f", + audioChannel, mixMicrophone, volumeScaling); + return -1; + } + _audioChannelsSending.Insert(audioChannel, NULL); + + CriticalSectionScoped lock(*_ptrAudioCritSect); + _audioClients++; // Increase the number of audioClients; + + return 0; +} + +// ---------------------------------------------------------------------------- +// StopSendAudioOnChannel +// Order the voice engine to stop send the audio on a channel +// ---------------------------------------------------------------------------- +int ViEFilePlayer::StopSendAudioOnChannel(const int audioChannel) +{ + int result = 0; + MapItem* audioItem = _audioChannelsSending.Find(audioChannel); + if (!audioItem) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "_s AudioChannel %d not sending", __FUNCTION__, audioChannel); + return -1; + } + result = _veFileInterface->StopPlayingFileAsMicrophone(audioChannel); + if (result != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "ViEFilePlayer::StopSendAudioOnChannel() VE_StopPlayingFileAsMicrophone failed. audioChannel %d", + audioChannel); + } + _audioChannelsSending.Erase(audioItem); + CriticalSectionScoped lock(*_ptrAudioCritSect); + _audioClients--; // Decrease the number of audioClients; + assert(_audioClients>=0); + return 0; + +} +int ViEFilePlayer::PlayAudioLocally(const int audioChannel, float volumeScaling) +{ + if (!_veFileInterface) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s No VEFile interface.", __FUNCTION__); + return -1; + } + if (_veFileInterface->StartPlayingFileLocally( + audioChannel, + this, + kFileFormatPcm16kHzFile, + volumeScaling) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s VE_StartPlayingFileAsMicrophone failed. audioChannel %d, mixMicrophone %d, volumeScaling %.2f", + __FUNCTION__, audioChannel, volumeScaling); + return -1; + } + + CriticalSectionScoped lock(*_ptrAudioCritSect); + _localAudioChannel = audioChannel; + _audioClients++; // Increase the number of audioClients; + + return 0; + +} + +int ViEFilePlayer::StopPlayAudioLocally(const int audioChannel) +{ + if (!_veFileInterface) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s No VEFile interface.", __FUNCTION__); + return -1; + } + if (_veFileInterface->StopPlayingFileLocally(audioChannel) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s VE_StopPlayingFileLocally failed. audioChannel %d.", + __FUNCTION__, audioChannel); + return -1; + } + + CriticalSectionScoped lock(*_ptrAudioCritSect); + _localAudioChannel = -1; + _audioClients--; // Decrease the number of audioClients; + + return 0; + +} + +//static +int ViEFilePlayer::GetFileInformation(int engineId, const char* fileName, + VideoCodec& videoCodec, + webrtc::CodecInst& audioCodec, + const webrtc::FileFormats fileFormat) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, engineId, "%s ", __FUNCTION__); + + FilePlayer* filePlayer = FilePlayer::CreateFilePlayer(engineId, fileFormat); + if (!filePlayer) + { + return -1; + } + int result = 0; + + bool videoOnly = false; + + memset(&videoCodec, 0, sizeof(videoCodec)); + memset(&audioCodec, 0, sizeof(audioCodec)); + + if (filePlayer->StartPlayingVideoFile(fileName, false, false) != 0) + { + videoOnly = true; + if (filePlayer->StartPlayingVideoFile(fileName, false, true) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, engineId, + "%s Failed to open file.", __FUNCTION__); + FilePlayer::DestroyFilePlayer(filePlayer); + return -1; + } + } + + if (!videoOnly && filePlayer->AudioCodec(audioCodec) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, engineId, + "%s Failed to get audio codec.", __FUNCTION__); + FilePlayer::DestroyFilePlayer(filePlayer); + return -1; + } + if (filePlayer->video_codec_info(videoCodec) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, engineId, + "%s Failed to get video codec.", __FUNCTION__); + FilePlayer::DestroyFilePlayer(filePlayer); + return -1; + } + FilePlayer::DestroyFilePlayer(filePlayer); + return 0; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_file_player.h b/video_engine/main/source/vie_file_player.h new file mode 100644 index 0000000000..cfe0f96ce6 --- /dev/null +++ b/video_engine/main/source/vie_file_player.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_file_player.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_PLAYER_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_PLAYER_H_ + +#include "typedefs.h" +#include "common_types.h" // webrtc::OutStream +#include "file_player.h" +#include "media_file_defines.h" +#include "vie_file.h" +#include "voe_file.h" +#include "voe_video_sync.h" +#include "list_wrapper.h" +#include "vie_frame_provider_base.h" +#include "file_wrapper.h" + +namespace webrtc +{ +class EventWrapper; +class ThreadWrapper; +class ViEInputManager; +class ViEFilePlayer: public ViEFrameProviderBase, + protected webrtc::FileCallback, + protected webrtc::InStream // for audio +{ +public: + static ViEFilePlayer *CreateViEFilePlayer(int fileId, int engineId, + const char* fileNameUTF8, + const bool loop, + const webrtc::FileFormats fileFormat, + ViEInputManager& inputManager, + VoiceEngine* vePtr); + + static int GetFileInformation(const int engineId, + const char* fileName, + webrtc::VideoCodec& videoCodec, + webrtc::CodecInst& audioCodec, + const webrtc::FileFormats fileFormat); + ~ViEFilePlayer(); + + bool IsObserverRegistered(); + int RegisterObserver(ViEFileObserver& observer); + int DeRegisterObserver(); + int SendAudioOnChannel(const int audioChannel, bool mixMicrophone, + float volumeScaling); + int StopSendAudioOnChannel(const int audioChannel); + int PlayAudioLocally(const int audioChannel, float volumeScaling); + int StopPlayAudioLocally(const int audioChannel); + + //Implement ViEFrameProviderBase + virtual int FrameCallbackChanged(); + +protected: + ViEFilePlayer(int Id, int engineId, ViEInputManager& inputManager); + int Init(const WebRtc_Word8* fileNameUTF8, const bool loop, + const webrtc::FileFormats fileFormat, VoiceEngine* vePtr); + int StopPlay(); + int StopPlayAudio(); + + // File play decode function. + static bool FilePlayDecodeThreadFunction(void* obj); + bool FilePlayDecodeProcess(); + bool NeedsAudioFromFile(void* buf); + + // From webrtc::InStream + virtual int Read(void *buf, int len); + virtual int Rewind() { return 0;} + + // From FileCallback + virtual void PlayNotification(const WebRtc_Word32 /*id*/, + const WebRtc_UWord32 /*notificationMs*/){} + virtual void RecordNotification(const WebRtc_Word32 id, + const WebRtc_UWord32 notificationMs){} + virtual void PlayFileEnded(const WebRtc_Word32 id); + virtual void RecordFileEnded(const WebRtc_Word32 id) { } + + +private: + enum { kThreadWaitTimeMs = 100 }; + + bool _playBackStarted; + ViEInputManager& _inputManager; + + CriticalSectionWrapper* _ptrFeedBackCritSect; + CriticalSectionWrapper* _ptrAudioCritSect; + + webrtc::FilePlayer* _filePlayer; + bool _audioStream; + + int _videoClients; // Number of active video clients + int _audioClients; //No of audio channels sending this audio. + int _localAudioChannel; //Local audio channel playing this video. Sync video against this. + + ViEFileObserver* _observer; + WebRtc_Word8 _fileName[FileWrapper::kMaxFileNameSize]; + + // VE Interface + VoEFile* _veFileInterface; + VoEVideoSync* _veVideoSync; + // Thread for decoding video (and audio if no audio clients connected) + ThreadWrapper* _ptrDecodeThread; + EventWrapper* _ptrDecodeEvent; + WebRtc_Word16 _decodedAudio[320]; + WebRtc_UWord32 _decodedAudioLength; + + ListWrapper _audioChannelBuffers; //trick - list containing VE buffer reading this file. Used if multiple audio channels are sending. + MapWrapper _audioChannelsSending; // AudioChannels sending audio from this file + VideoFrame _decodedVideo; // Frame receiving decoded video from file. +}; +} // namespace webrtc + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_PLAYER_H_ diff --git a/video_engine/main/source/vie_file_recorder.cc b/video_engine/main/source/vie_file_recorder.cc new file mode 100644 index 0000000000..547cc1449c --- /dev/null +++ b/video_engine/main/source/vie_file_recorder.cc @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_file_recorder.cc + * + */ +#include "vie_file_recorder.h" +#include "critical_section_wrapper.h" +#include "trace.h" +#include "tick_util.h" +#include "file_player.h" +#include "file_recorder.h" +#include "vie_defines.h" + +namespace webrtc { + +ViEFileRecorder::ViEFileRecorder(int instanceID) + : _ptrCritSec(CriticalSectionWrapper::CreateCriticalSection()), + _fileRecorder(NULL), _isFirstFrameRecorded(false), + _isOutStreamStarted(false), _instanceID(instanceID), _frameDelay(0), + _audioChannel(-1), _audioSource(NO_AUDIO), + _veFileInterface(NULL) +{ +} + +ViEFileRecorder::~ViEFileRecorder() +{ + StopRecording(); + delete _ptrCritSec; +} + +int ViEFileRecorder::StartRecording(const char* fileNameUTF8, + const VideoCodec& codecInst, + AudioSource audioSource, + int audioChannel, + const webrtc::CodecInst audioCodecInst, + VoiceEngine* vePtr, + const webrtc::FileFormats fileFormat) +{ + CriticalSectionScoped lock(*_ptrCritSec); + + if (_fileRecorder) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID, + "ViEFileRecorder::StartRecording() failed, already recording."); + return -1; + } + _fileRecorder = FileRecorder::CreateFileRecorder(_instanceID, fileFormat); + if (!_fileRecorder) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID, + "ViEFileRecorder::StartRecording() failed to create file recoder."); + return -1; + } + + int error = _fileRecorder->StartRecordingVideoFile(fileNameUTF8, + audioCodecInst, + codecInst, + AMRFileStorage, + audioSource == NO_AUDIO); + if (error) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID, + "ViEFileRecorder::StartRecording() failed to StartRecordingVideoFile."); + FileRecorder::DestroyFileRecorder(_fileRecorder); + _fileRecorder = NULL; + return -1; + } + + _audioSource = audioSource; + if (vePtr && audioSource != NO_AUDIO) // VeInterface have been provided and we want to record audio + { + _veFileInterface = VoEFile::GetInterface(vePtr); + if (!_veFileInterface) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID, + "ViEFileRecorder::StartRecording() failed to get VEFile interface"); + return -1; + } + // always drive VoE in L16 + CodecInst engineAudioCodecInst = { 96, // .pltype + "L16", // .plname + audioCodecInst.plfreq, // .plfreq + audioCodecInst.plfreq / 100, // .pacsize (10ms) + 1, // .channels + audioCodecInst.plfreq * 16 // .rate + }; + + switch (audioSource) + { + case MICROPHONE: + error + = _veFileInterface->StartRecordingMicrophone( + this, + &engineAudioCodecInst); + break; + case PLAYOUT: + error + = _veFileInterface->StartRecordingPlayout( + audioChannel, + this, + &engineAudioCodecInst); + break; + case NO_AUDIO: + break; + default: + assert(!"Unknown audioSource"); + } + if (error != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID, + "ViEFileRecorder::StartRecording() failed to start recording audio"); + FileRecorder::DestroyFileRecorder(_fileRecorder); + _fileRecorder = NULL; + return -1; + } + _isOutStreamStarted = true; + _audioChannel = audioChannel; + } + + _isFirstFrameRecorded = false; + return 0; +} + +int ViEFileRecorder::StopRecording() +{ + + int error; + // Stop recording audio + // Note - we can not hold the _ptrCritSect while accessing VE functions. It might cause deadlock in Write + if (_veFileInterface) + { + switch (_audioSource) + { + case MICROPHONE: + error = _veFileInterface->StopRecordingMicrophone(); + break; + case PLAYOUT: + error = _veFileInterface->StopRecordingPlayout(_audioChannel); + break; + case NO_AUDIO: + break; + default: + assert(!"Unknown audioSource"); + } + if (error != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID, + "ViEFileRecorder::StopRecording() failed to stop recording audio"); + } + } + CriticalSectionScoped lock(*_ptrCritSec); + if (_veFileInterface) + { + _veFileInterface->Release(); + _veFileInterface = NULL; + } + + if (_fileRecorder) + { + if (_fileRecorder->IsRecording()) + { + int error = _fileRecorder->StopRecording(); + if (error) + { + return -1; + } + } + FileRecorder::DestroyFileRecorder(_fileRecorder); + _fileRecorder = NULL; + } + _isFirstFrameRecorded = false; + _isOutStreamStarted = false; + return 0; +} + +void ViEFileRecorder::SetFrameDelay(int frameDelay) +{ + CriticalSectionScoped lock(*_ptrCritSec); + _frameDelay = frameDelay; +} + +bool ViEFileRecorder::RecordingStarted() +{ + CriticalSectionScoped lock(*_ptrCritSec); + return _fileRecorder && _fileRecorder->IsRecording(); +} + +bool ViEFileRecorder::FirstFrameRecorded() +{ + CriticalSectionScoped lock(*_ptrCritSec); + return _isFirstFrameRecorded; +} + +bool ViEFileRecorder::IsRecordingFileFormat(const webrtc::FileFormats fileFormat) +{ + CriticalSectionScoped lock(*_ptrCritSec); + return (_fileRecorder->RecordingFileFormat() == fileFormat) ? true : false; +} + +/******************************************************************************* + * void RecordVideoFrame() + * + * Records incoming decoded video frame to AVI-file. + * + */ +void ViEFileRecorder::RecordVideoFrame(const VideoFrame& videoFrame) +{ + CriticalSectionScoped lock(*_ptrCritSec); + + if (_fileRecorder && _fileRecorder->IsRecording()) + { + if (!IsRecordingFileFormat(webrtc::kFileFormatAviFile)) + { + return; + } + + //Compensate for frame delay in order to get audiosync when recording local video. + const WebRtc_UWord32 timeStamp = videoFrame.TimeStamp(); + const WebRtc_Word64 renderTimeStamp = videoFrame.RenderTimeMs(); + VideoFrame& unconstVideoFrame = + const_cast (videoFrame); + unconstVideoFrame.SetTimeStamp(timeStamp - 90 * _frameDelay); + unconstVideoFrame.SetRenderTime(renderTimeStamp - _frameDelay); + + _fileRecorder->RecordVideoToFile(unconstVideoFrame); + + unconstVideoFrame.SetRenderTime(renderTimeStamp); + unconstVideoFrame.SetTimeStamp(timeStamp); + } +} + +// --------------------- +// From OutStream +// --------------------- +// 10 ms block of PCM 16 +bool ViEFileRecorder::Write(const void* buf, int len) +{ + if (!_isOutStreamStarted) + return true; + + // always L16 from VoCE + if (len % (2 * 80)) // 2 bytes 80 samples + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _audioChannel, + "Audio length not supported: %d.", len); + return true; + } + AudioFrame audioFrame; + WebRtc_UWord16 lengthInSamples = len / 2; + + audioFrame.UpdateFrame(_audioChannel, 0, (const WebRtc_Word16*) buf, + lengthInSamples, lengthInSamples * 100, + AudioFrame::kUndefined, + AudioFrame::kVadUnknown); + + CriticalSectionScoped lock(*_ptrCritSec); + + if (_fileRecorder && _fileRecorder->IsRecording()) + { + TickTime tickTime = TickTime::Now(); + _fileRecorder->RecordAudioToFile(audioFrame, &tickTime); + } + return true; // Always return true! +} + +int ViEFileRecorder::Rewind() +{ + // Not supported! + return -1; +} +} // namespace webrtc + diff --git a/video_engine/main/source/vie_file_recorder.h b/video_engine/main/source/vie_file_recorder.h new file mode 100644 index 0000000000..bae96f11a3 --- /dev/null +++ b/video_engine/main/source/vie_file_recorder.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_file_recorder.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_RECORDER_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_RECORDER_H_ + +#include "typedefs.h" +#include "file_recorder.h" +#include "vie_file.h" +#include "voe_file.h" + +namespace webrtc { +class CriticalSectionWrapper; + +class ViEFileRecorder: protected webrtc::OutStream // for audio +{ +public: + ViEFileRecorder(int channelId); + ~ViEFileRecorder(); + + int StartRecording(const char* fileNameUTF8, + const webrtc::VideoCodec& codecInst, + AudioSource audioSource, int audioChannel, + const webrtc::CodecInst audioCodecInst, + VoiceEngine* vePtr, + const webrtc::FileFormats fileFormat = webrtc::kFileFormatAviFile); + int StopRecording(); + void SetFrameDelay(int frameDelay); + bool RecordingStarted(); + void RecordVideoFrame(const VideoFrame& videoFrame); + +protected: + bool FirstFrameRecorded(); + bool IsRecordingFileFormat(const webrtc::FileFormats fileFormat); + // From webrtc::OutStream + bool Write(const void* buf, int len); + int Rewind(); + +private: + CriticalSectionWrapper* _ptrCritSec; + + FileRecorder* _fileRecorder; + bool _isFirstFrameRecorded; + bool _isOutStreamStarted; + int _instanceID; + int _frameDelay; + int _audioChannel; + AudioSource _audioSource; + VoEFile* _veFileInterface; +}; + +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_RECORDER_H_ diff --git a/video_engine/main/source/vie_frame_provider_base.cc b/video_engine/main/source/vie_frame_provider_base.cc new file mode 100644 index 0000000000..0fda87da9a --- /dev/null +++ b/video_engine/main/source/vie_frame_provider_base.cc @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vie_frame_provider_base.h" +#include "critical_section_wrapper.h" +#include "tick_util.h" +#include "trace.h" +#include "vie_defines.h" + +namespace webrtc { + +ViEFrameProviderBase::ViEFrameProviderBase(int Id, int engineId): +_id(Id), +_engineId(engineId), +_frameCallbackMap(), +_providerCritSect(*CriticalSectionWrapper::CreateCriticalSection()), +_ptrExtraFrame(NULL), +_frameDelay(0) +{ +} + +ViEFrameProviderBase::~ViEFrameProviderBase() +{ + if(_frameCallbackMap.Size()>0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId,_id), "FramCallbacks still exist when Provider deleted %d",_frameCallbackMap.Size()); + } + for(MapItem* item=_frameCallbackMap.First();item!=NULL;item=_frameCallbackMap.Next(item)) + { + static_cast(item->GetItem())->ProviderDestroyed(_id); + } + + while(_frameCallbackMap.Erase(_frameCallbackMap.First()) == 0) + ; + + delete &_providerCritSect; + delete _ptrExtraFrame; +} + +int ViEFrameProviderBase::Id() +{ + return _id; +} + +void ViEFrameProviderBase::DeliverFrame(webrtc::VideoFrame& videoFrame,int numCSRCs, + const WebRtc_UWord32 CSRC[kRtpCsrcSize]) +{ +#ifdef _DEBUG + const TickTime startProcessTime=TickTime::Now(); +#endif + CriticalSectionScoped cs(_providerCritSect); + + // Deliver the frame to all registered callbacks + if (_frameCallbackMap.Size() > 0) + { + if(_frameCallbackMap.Size()==1) + { + ViEFrameCallback* frameObserver = static_cast(_frameCallbackMap.First()->GetItem()); + frameObserver->DeliverFrame(_id,videoFrame,numCSRCs,CSRC); + } + else + { + // Make a copy of the frame for all callbacks + for (MapItem* mapItem = _frameCallbackMap.First(); + mapItem != NULL; + mapItem = _frameCallbackMap.Next(mapItem)) + { + if (_ptrExtraFrame == NULL) + { + _ptrExtraFrame = new webrtc::VideoFrame(); + } + if (mapItem != NULL) + { + ViEFrameCallback* frameObserver = static_cast(mapItem->GetItem()); + if (frameObserver != NULL) + { + // We must copy the frame each time since the previous receiver might swap it... + _ptrExtraFrame->CopyFrame(videoFrame); + frameObserver->DeliverFrame(_id, *_ptrExtraFrame,numCSRCs,CSRC); + } + } + } + } + } + +#ifdef _DEBUG + const int processTime=(int) (TickTime::Now()-startProcessTime).Milliseconds(); + if(processTime>25) // Warn If the delivery time is too long. + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId,_id), "%s Too long time: %ums",__FUNCTION__,processTime); + } +#endif +} + +void ViEFrameProviderBase::SetFrameDelay(int frameDelay) +{ + + CriticalSectionScoped cs(_providerCritSect); + _frameDelay=frameDelay; + + for (MapItem* mapItem = _frameCallbackMap.First(); + mapItem != NULL; + mapItem = _frameCallbackMap.Next(mapItem)) + { + ViEFrameCallback* frameObserver = static_cast(mapItem->GetItem()); + assert(frameObserver); + frameObserver->DelayChanged(_id,frameDelay); + } + +} + +int ViEFrameProviderBase::FrameDelay() +{ + return _frameDelay; +} + +int ViEFrameProviderBase::GetBestFormat(int& bestWidth, + int& bestHeight, + int& bestFrameRate) +{ + + int largestWidth = 0; + int largestHeight = 0; + int highestFrameRate = 0; + + CriticalSectionScoped cs(_providerCritSect); + + // Check if this one already exists... + for (MapItem* mapItem = _frameCallbackMap.First(); + mapItem != NULL; + mapItem = _frameCallbackMap.Next(mapItem)) + { + + + int preferedWidth=0; + int preferedHeight=0; + int preferedFrameRate=0; + + ViEFrameCallback* callbackObject = static_cast(mapItem->GetItem()); + assert(callbackObject); + if(callbackObject->GetPreferedFrameSettings(preferedWidth,preferedHeight,preferedFrameRate)==0) + { + if (preferedWidth > largestWidth) + { + largestWidth = preferedWidth; + } + if (preferedHeight > largestHeight) + { + largestHeight = preferedHeight; + } + if (preferedFrameRate > highestFrameRate) + { + highestFrameRate = preferedFrameRate; + } + } + } + + bestWidth = largestWidth; + bestHeight = largestHeight; + bestFrameRate = highestFrameRate; + + return 0; +} + +int ViEFrameProviderBase::RegisterFrameCallback(int observerId,ViEFrameCallback* callbackObject) +{ + if (callbackObject == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s: No argument", __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s(0x%p)", callbackObject); + + { + CriticalSectionScoped cs(_providerCritSect); + + // Check if this one already exists... + for (MapItem* mapItem = _frameCallbackMap.First(); + mapItem != NULL; + mapItem = _frameCallbackMap.Next(mapItem)) + { + const ViEFrameCallback* observer=static_cast (mapItem->GetItem()); + if (observer == callbackObject) + { + // This callback is already registered + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s 0x%p already registered", __FUNCTION__, callbackObject); + + assert("!frameObserver already registered"); + return -1; + } + } + + if (_frameCallbackMap.Insert(observerId,callbackObject) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s: Could not add 0x%p to list", __FUNCTION__, callbackObject); + return -1; + } + } + // Report current capture delay + callbackObject->DelayChanged(_id,_frameDelay); + + FrameCallbackChanged(); // Notify implementer of this class that the callback list have changed + return 0; + + +} + + +// ---------------------------------------------------------------------------- +// DeregisterFrameCallback +// ---------------------------------------------------------------------------- + +int ViEFrameProviderBase::DeregisterFrameCallback(const ViEFrameCallback* callbackObject) +{ + if (callbackObject == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s: No argument", __FUNCTION__); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s(0x%p)", callbackObject); + + + { + CriticalSectionScoped cs(_providerCritSect); + bool itemFound=false; + + + // Try to find the callback in our list + for (MapItem* mapItem = _frameCallbackMap.First(); + mapItem != NULL; + mapItem = _frameCallbackMap.Next(mapItem)) + { + const ViEFrameCallback* observer=static_cast (mapItem->GetItem()); + if (observer == callbackObject) + { + // We found it, remove it! + _frameCallbackMap.Erase(mapItem); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s 0x%p deregistered", __FUNCTION__, callbackObject); + itemFound=true; + break; + } + } + if(!itemFound) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s 0x%p not found", __FUNCTION__, callbackObject); + return -1; + } + } + + FrameCallbackChanged(); // Notify implementer of this class that the callback list have changed + return 0; +} + +// ---------------------------------------------------------------------------- +// IsFrameCallbackRegistered +// ---------------------------------------------------------------------------- + +bool ViEFrameProviderBase::IsFrameCallbackRegistered(const ViEFrameCallback* callbackObject) +{ + if (callbackObject == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s: No argument", __FUNCTION__); + return false; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s(0x%p)", callbackObject); + + for (MapItem* mapItem = _frameCallbackMap.First(); + mapItem != NULL; + mapItem = _frameCallbackMap.Next(mapItem)) + { + if (callbackObject == mapItem->GetItem()) + { + // We found the callback + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s 0x%p is registered", __FUNCTION__, callbackObject); + return true; + } + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), + "%s 0x%p not registered", __FUNCTION__, callbackObject); + return false; +} + +// ---------------------------------------------------------------------------- +// NumberOfRegistersFrameCallbacks +// ---------------------------------------------------------------------------- + +int ViEFrameProviderBase::NumberOfRegistersFrameCallbacks() +{ + CriticalSectionScoped cs(_providerCritSect); + return _frameCallbackMap.Size(); +} +} // namespac webrtc diff --git a/video_engine/main/source/vie_frame_provider_base.h b/video_engine/main/source/vie_frame_provider_base.h new file mode 100644 index 0000000000..aa32a1f6c2 --- /dev/null +++ b/video_engine/main/source/vie_frame_provider_base.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_frame_provider_base.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FRAME_PROVIDER_BASE_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FRAME_PROVIDER_BASE_H_ + +// Defines +#include "typedefs.h" +#include "module_common_types.h" +#include "map_wrapper.h" + +namespace webrtc { +class CriticalSectionWrapper; +class VideoEncoder; + +class ViEFrameCallback +{ +public: + virtual void DeliverFrame(int id, VideoFrame& videoFrame, int numCSRCs = 0, + const WebRtc_UWord32 CSRC[kRtpCsrcSize] = NULL) = 0; + /* + * Delay has changed from the provider. + * frameDelay new capture delay in Ms. + */ + virtual void DelayChanged(int id, int frameDelay)=0; + + /* + Fetch the width, height and frame rate preferred by this observer. + return 0 on success, -1 otherwise. + */ + virtual int GetPreferedFrameSettings(int &width, int &height, + int &frameRate)=0; + + virtual void ProviderDestroyed(int id) = 0; + +protected: + virtual ~ViEFrameCallback() + { + } + ; +}; + +class ViEFrameProviderBase +{ +public: + ViEFrameProviderBase(int Id, int engineId); + virtual ~ViEFrameProviderBase(); + int Id(); + + // Register frame callbacks, i.e. a receiver of the captured frame. + virtual int RegisterFrameCallback(int observerId, + ViEFrameCallback* callbackObject); + virtual int + DeregisterFrameCallback(const ViEFrameCallback* callbackObject); + virtual bool + IsFrameCallbackRegistered(const ViEFrameCallback* callbackObject); + + int NumberOfRegistersFrameCallbacks(); + + // FrameCallbackChanged + // Inherited classes should check for new frameSettings and reconfigure output if possible. + // Return 0 on success, -1 otherwise. + virtual int FrameCallbackChanged() = 0; + +protected: + void DeliverFrame(VideoFrame& videoFrame, int numCSRCs = 0, + const WebRtc_UWord32 CSRC[kRtpCsrcSize] = NULL); + void SetFrameDelay(int frameDelay); + int FrameDelay(); + int GetBestFormat(int& bestWidth, int& bestHeight, int& bestFrameRate); + + int _id; + int _engineId; + +protected: + // Frame callbacks + MapWrapper _frameCallbackMap; + CriticalSectionWrapper& _providerCritSect; +private: + + VideoFrame* _ptrExtraFrame; + + //Members + int _frameDelay; + +}; + +} //namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FRAME_PROVIDER_BASE_H_ diff --git a/video_engine/main/source/vie_image_process_impl.cc b/video_engine/main/source/vie_image_process_impl.cc new file mode 100644 index 0000000000..4908d0c657 --- /dev/null +++ b/video_engine/main/source/vie_image_process_impl.cc @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_image_process_impl.cpp + */ +#include "vie_image_process_impl.h" + +// Defines +#include "vie_defines.h" + +#include "trace.h" +#include "vie_errors.h" +#include "vie_impl.h" +#include "vie_channel.h" +#include "vie_channel_manager.h" +#include "vie_encoder.h" +#include "vie_input_manager.h" +#include "vie_capturer.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// GetInterface +// ---------------------------------------------------------------------------- + +ViEImageProcess* ViEImageProcess::GetInterface(VideoEngine* videoEngine) +{ +#ifdef WEBRTC_VIDEO_ENGINE_IMAGE_PROCESS_API + if (videoEngine == NULL) + { + return NULL; + } + VideoEngineImpl* vieImpl = reinterpret_cast (videoEngine); + ViEImageProcessImpl* vieImageProcessImpl = vieImpl; + (*vieImageProcessImpl)++; // Increase ref count + + return vieImageProcessImpl; +#else + return NULL; +#endif +} + +// ---------------------------------------------------------------------------- +// Release +// +// Releases the interface, i.e. reduces the reference counter. The number of +// remaining references is returned, -1 if released too many times. +// ---------------------------------------------------------------------------- + +int ViEImageProcessImpl::Release() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "ViEImageProcess::Release()"); + (*this)--; // Decrease ref count + + WebRtc_Word32 refCount = GetCount(); + if (refCount < 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, + "ViEImageProcess release too many times"); + SetLastError(kViEAPIDoesNotExist); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId, + "ViEImageProcess reference count: %d", refCount); + return refCount; +} + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViEImageProcessImpl::ViEImageProcessImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViEImageProcessImpl::ViEImageProcessImpl() Ctor"); +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViEImageProcessImpl::~ViEImageProcessImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViEImageProcessImpl::~ViEImageProcessImpl() Dtor"); +} + +// ============================================================================ +// Effect filter +// ============================================================================ + +// ---------------------------------------------------------------------------- +// RegisterCaptureEffectFilter +// +// Registers an effect filter for a capture device +// ---------------------------------------------------------------------------- + +int ViEImageProcessImpl::RegisterCaptureEffectFilter( + const int captureId, ViEEffectFilter& captureFilter) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(captureId: %d)", __FUNCTION__, captureId); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + ViEInputManagerScoped is(_inputManager); + ViECapturer* vieCapture = is.Capture(captureId); + if (vieCapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViEImageProcessInvalidCaptureId); + return -1; + } + + if (vieCapture->RegisterEffectFilter(&captureFilter) != 0) + { + SetLastError(kViEImageProcessFilterExists); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterCaptureEffectFilter +// +// Deregisters a previously set fffect filter +// ---------------------------------------------------------------------------- + +int ViEImageProcessImpl::DeregisterCaptureEffectFilter(const int captureId) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(captureId: %d)", __FUNCTION__, captureId); + + ViEInputManagerScoped is(_inputManager); + ViECapturer* vieCapture = is.Capture(captureId); + if (vieCapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViEImageProcessInvalidCaptureId); + return -1; + } + if (vieCapture->RegisterEffectFilter(NULL) != 0) + { + SetLastError(kViEImageProcessFilterDoesNotExist); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterSendEffectFilter +// +// Registers an effect filter for a channel +// ---------------------------------------------------------------------------- + +int ViEImageProcessImpl::RegisterSendEffectFilter(const int videoChannel, + ViEEffectFilter& sendFilter) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(videoChannel: %d)", __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (vieEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Channel %d doesn't exist", __FUNCTION__, videoChannel); + SetLastError(kViEImageProcessInvalidChannelId); + return -1; + } + + if (vieEncoder->RegisterEffectFilter(&sendFilter) != 0) + { + SetLastError(kViEImageProcessFilterExists); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterSendEffectFilter +// +// Deregisters a previously set effect filter +// ---------------------------------------------------------------------------- + +int ViEImageProcessImpl::DeregisterSendEffectFilter(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(videoChannel: %d)", __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEEncoder* vieEncoder = cs.Encoder(videoChannel); + if (vieEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Channel %d doesn't exist", __FUNCTION__, videoChannel); + SetLastError(kViEImageProcessInvalidChannelId); + return -1; + } + if (vieEncoder->RegisterEffectFilter(NULL) != 0) + { + SetLastError(kViEImageProcessFilterDoesNotExist); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterRenderEffectFilter +// +// Registers an effect filter for an incoming decoded stream +// ---------------------------------------------------------------------------- + +int ViEImageProcessImpl::RegisterRenderEffectFilter( + const int videoChannel, ViEEffectFilter& renderFilter) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(videoChannel: %d)", __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Channel %d doesn't exist", __FUNCTION__, videoChannel); + SetLastError(kViEImageProcessInvalidChannelId); + return -1; + } + + if (vieChannel->RegisterEffectFilter(&renderFilter) != 0) + { + SetLastError(kViEImageProcessFilterExists); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterRenderEffectFilter +// +// ---------------------------------------------------------------------------- + +int ViEImageProcessImpl::DeregisterRenderEffectFilter(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(videoChannel: %d)", __FUNCTION__, videoChannel); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Channel %d doesn't exist", __FUNCTION__, videoChannel); + SetLastError(kViEImageProcessInvalidChannelId); + return -1; + } + + if (vieChannel->RegisterEffectFilter(NULL) != 0) + { + SetLastError(kViEImageProcessFilterDoesNotExist); + return -1; + } + return 0; +} + +// ============================================================================ +// Image enhancement +// ============================================================================ + +// ---------------------------------------------------------------------------- +// EnableDeflickering +// +// Enables/disables deflickering of the captured image. +// ---------------------------------------------------------------------------- + +int ViEImageProcessImpl::EnableDeflickering(const int captureId, + const bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(captureId: %d, enable: %d)", __FUNCTION__, captureId, enable); + + ViEInputManagerScoped is(_inputManager); + ViECapturer* vieCapture = is.Capture(captureId); + if (vieCapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViEImageProcessInvalidChannelId); + return -1; + } + + if (vieCapture->EnableDeflickering(enable) != 0) + { + if (enable) + SetLastError(kViEImageProcessAlreadyEnabled); + else + { + SetLastError(kViEImageProcessAlreadyDisabled); + } + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// EnableDenoising +// +// Enables/disables denoising of the captured image. +// ---------------------------------------------------------------------------- + +int ViEImageProcessImpl::EnableDenoising(const int captureId, const bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(captureId: %d, enable: %d)", __FUNCTION__, captureId, enable); + + ViEInputManagerScoped is(_inputManager); + ViECapturer* vieCapture = is.Capture(captureId); + if (vieCapture == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Capture device %d doesn't exist", __FUNCTION__, + captureId); + SetLastError(kViEImageProcessInvalidCaptureId); + return -1; + } + + if (vieCapture->EnableDenoising(enable) != 0) + { + if (enable) + SetLastError(kViEImageProcessAlreadyEnabled); + else + { + SetLastError(kViEImageProcessAlreadyDisabled); + } + return -1; + } + return 0; + +} + +// ---------------------------------------------------------------------------- +// EnableColorEnhancement +// +// Enables coloe enhancement for decoded images +// ---------------------------------------------------------------------------- + +int ViEImageProcessImpl::EnableColorEnhancement(const int videoChannel, + const bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(videoChannel: %d, enable: %d)", __FUNCTION__, videoChannel, + enable); + + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* vieChannel = cs.Channel(videoChannel); + if (vieChannel == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Channel %d doesn't exist", __FUNCTION__, videoChannel); + SetLastError(kViEImageProcessInvalidChannelId); + return -1; + } + if (vieChannel->EnableColorEnhancement(enable) != 0) + { + if (enable) + SetLastError(kViEImageProcessAlreadyEnabled); + else + { + SetLastError(kViEImageProcessAlreadyDisabled); + } + return -1; + } + return 0; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_image_process_impl.h b/video_engine/main/source/vie_image_process_impl.h new file mode 100644 index 0000000000..d7494da4ad --- /dev/null +++ b/video_engine/main/source/vie_image_process_impl.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_image_process_impl.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_IMAGE_PROCESS_IMPL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_IMAGE_PROCESS_IMPL_H_ + +#include "typedefs.h" +#include "vie_ref_count.h" +#include "vie_image_process.h" +#include "vie_shared_data.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// ViEImageProcessImpl +// ---------------------------------------------------------------------------- + +class ViEImageProcessImpl: public virtual ViESharedData, + public ViEImageProcess, + public ViERefCount +{ +public: + virtual int Release(); + + // Effect filter + virtual int RegisterCaptureEffectFilter(const int captureId, + ViEEffectFilter& captureFilter); + + virtual int DeregisterCaptureEffectFilter(const int captureId); + + virtual int RegisterSendEffectFilter(const int videoChannel, + ViEEffectFilter& sendFilter); + + virtual int DeregisterSendEffectFilter(const int videoChannel); + + virtual int RegisterRenderEffectFilter(const int videoChannel, + ViEEffectFilter& renderFilter); + + virtual int DeregisterRenderEffectFilter(const int videoChannel); + + // Image enhancement + virtual int EnableDeflickering(const int captureId, const bool enable); + + virtual int EnableDenoising(const int captureId, const bool enable); + + virtual int EnableColorEnhancement(const int videoChannel, + const bool enable); + +protected: + ViEImageProcessImpl(); + virtual ~ViEImageProcessImpl(); +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_IMAGE_PROCESS_IMPL_H_ diff --git a/video_engine/main/source/vie_impl.cc b/video_engine/main/source/vie_impl.cc new file mode 100644 index 0000000000..2f7af5b713 --- /dev/null +++ b/video_engine/main/source/vie_impl.cc @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_impl.cc + */ + +#include "vie_impl.h" +#include "trace.h" + +#if (defined(_WIN32) || defined(_WIN64)) +#include // For LoadLibrary +#include // For _T +#endif + +#ifdef ANDROID +#include "video_capture.h" +#include "video_render.h" +#endif + +// Global counter to get an id for each new ViE instance +static WebRtc_Word32 gViEActiveInstanceCounter = 0; + +namespace webrtc +{ + +// ------------------------------------------------------------------------- +// GetVideoEngine (C-function) +// +// extern "C" ensures that GetProcAddress() can find the function address +// ------------------------------------------------------------------------- + +extern "C" +{ +VideoEngine* GetVideoEngine(); + +VideoEngine* GetVideoEngine() +{ + VideoEngineImpl* self = new VideoEngineImpl(); + if (self == NULL) + { + return NULL; + } + gViEActiveInstanceCounter++; + VideoEngine* vie = reinterpret_cast (self); + return vie; +} +} + +// ------------------------------------------------------------------------- +// Create +// ------------------------------------------------------------------------- + +VideoEngine* VideoEngine::Create() +{ +#if (defined(_WIN32) || defined(_WIN64)) + // Load a debug dll, if there is one... + HMODULE hmod_ = LoadLibrary(TEXT("VideoEngineTestingDLL.dll")); + if (hmod_) + { + typedef VideoEngine* (*PFNGetVideoEngineLib)(void); + PFNGetVideoEngineLib pfn = + (PFNGetVideoEngineLib)GetProcAddress(hmod_,"GetVideoEngine"); + if (pfn) + { + VideoEngine* self = pfn(); + return self; + } + else + { + assert(!"Failed to open test dll VideoEngineTestingDLL.dll"); + return NULL; + } + } +#endif + + return GetVideoEngine(); +} + +// ------------------------------------------------------------------------- +// Delete +// +// Deletes the VideoEngineImpl instance if all reference counters are +// down to zero. +// ------------------------------------------------------------------------- + +bool VideoEngine::Delete(VideoEngine*& videoEngine) +{ + if (videoEngine == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "VideoEngine::Delete - No argument"); + return false; + } + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "VideoEngine::Delete( vie = 0x%p)", videoEngine); + + VideoEngineImpl* vieImpl = reinterpret_cast (videoEngine); + + // Check all reference counters + ViEBaseImpl* vieBase = vieImpl; + if (vieBase->GetCount() > 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "ViEBase ref count: %d", vieBase->GetCount()); + return false; + } +#ifdef WEBRTC_VIDEO_ENGINE_CAPTURE_API + ViECaptureImpl* vieCapture = vieImpl; + if (vieCapture->GetCount() > 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "ViECapture ref count: %d", vieCapture->GetCount()); + return false; + } +#endif +#ifdef WEBRTC_VIDEO_ENGINE_CODEC_API + ViECodecImpl* vieCodec = vieImpl; + if (vieCodec->GetCount() > 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "ViECodec ref count: %d", vieCodec->GetCount()); + return false; + } +#endif +#ifdef WEBRTC_VIDEO_ENGINE_ENCRYPTION_API + ViEEncryptionImpl* vieEncryption = vieImpl; + if (vieEncryption->GetCount() > 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "ViEEncryption ref count: %d", vieEncryption->GetCount()); + return false; + } +#endif +#ifdef WEBRTC_VIDEO_ENGINE_EXTERNAL_CODEC_API + ViEExternalCodecImpl* vieExternalCodec = vieImpl; + if (vieExternalCodec->GetCount() > 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "ViEEncryption ref count: %d", vieEncryption->GetCount()); + return false; + } +#endif +#ifdef WEBRTC_VIDEO_ENGINE_FILE_API + ViEFileImpl* vieFile = vieImpl; + if (vieFile->GetCount() > 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "ViEFile ref count: %d", vieFile->GetCount()); + return false; + } +#endif +#ifdef WEBRTC_VIDEO_ENGINE_IMAGE_PROCESS_API + ViEImageProcessImpl* vieImageProcess = vieImpl; + if (vieImageProcess->GetCount() > 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "ViEImageProcess ref count: %d", vieImageProcess->GetCount()); + return false; + } +#endif +#ifdef WEBRTC_VIDEO_ENGINE_NETWORK_API + ViENetworkImpl* vieNetwork = vieImpl; + if (vieNetwork->GetCount() > 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "ViENetwork ref count: %d", vieNetwork->GetCount()); + return false; + } +#endif +#ifdef WEBRTC_VIDEO_ENGINE_RENDER_API + ViERenderImpl* vieRender = vieImpl; + if (vieRender->GetCount() > 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "ViERender ref count: %d", vieRender->GetCount()); + return false; + } +#endif +#ifdef WEBRTC_VIDEO_ENGINE_RTP_RTCP_API + ViERTP_RTCPImpl* vieRtpRtcp = vieImpl; + if (vieRtpRtcp->GetCount() > 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "ViERTP_RTCP ref count: %d", vieRtpRtcp->GetCount()); + return false; + } +#endif + + // Delete VieImpl + delete vieImpl; + vieImpl = NULL; + videoEngine = NULL; + + // Decrease the number of instances + gViEActiveInstanceCounter--; + + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "%s: instance deleted. Remaining instances: %d", __FUNCTION__, + gViEActiveInstanceCounter); + + return true; +} + +// ------------------------------------------------------------------------- +// [static] SetTraceFile +// ------------------------------------------------------------------------- + +int VideoEngine::SetTraceFile(const char* fileNameUTF8, + const bool addFileCounter) +{ + if (fileNameUTF8 == NULL) + { + return -1; + } + if (Trace::SetTraceFile(fileNameUTF8, addFileCounter) == -1) + { + return -1; + } + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "SetTraceFileName(fileNameUTF8 = %s, addFileCounter = %d", + fileNameUTF8, addFileCounter); + return 0; +} + +// ------------------------------------------------------------------------- +// [static] SetTraceFilter +// ------------------------------------------------------------------------- + +int VideoEngine::SetTraceFilter(const unsigned int filter) +{ + WebRtc_UWord32 oldFilter = 0; + Trace::LevelFilter(oldFilter); + + if (filter == webrtc::kTraceNone && oldFilter != webrtc::kTraceNone) + { + // Do the logging before turning it off + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "SetTraceFilter(filter = 0x%x)", filter); + } + + WebRtc_Word32 error = Trace::SetLevelFilter(filter); + + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "SetTraceFilter(filter = 0x%x)", filter); + if (error != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "SetTraceFilter error: %d", error); + return -1; + } + + return 0; +} + +// ------------------------------------------------------------------------- +// [static] SetTraceFilter +// ------------------------------------------------------------------------- + +int VideoEngine::SetTraceCallback(webrtc::TraceCallback* callback) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "SetTraceCallback(webrtc::TraceCallback = 0x%p)", callback); + return Trace::SetTraceCallback(callback); +} + +// ------------------------------------------------------------------------- +// [static] SetAndroidObjects +// ------------------------------------------------------------------------- + +int VideoEngine::SetAndroidObjects(void* javaVM, void* javaContext) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "SetAndroidObjects()"); + +#ifdef ANDROID + if (VideoCaptureModule::SetAndroidObjects(javaVM,javaContext) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "Could not set capture module Android objects"); + return -1; + } + if (VideoRender::SetAndroidObjects(javaVM) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, gViEActiveInstanceCounter, + "Could not set render module Android objects"); + return -1; + } + return 0; +#else + return -1; +#endif +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_impl.h b/video_engine/main/source/vie_impl.h new file mode 100644 index 0000000000..bea2065c67 --- /dev/null +++ b/video_engine/main/source/vie_impl.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_impl.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_IMPL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_IMPL_H_ + +#include "engine_configurations.h" +#include "vie_defines.h" + +// Include all sub API:s + +#include "vie_base_impl.h" + +#ifdef WEBRTC_VIDEO_ENGINE_CAPTURE_API +#include "vie_capture_impl.h" +#endif +#ifdef WEBRTC_VIDEO_ENGINE_CODEC_API +#include "vie_codec_impl.h" +#endif +#ifdef WEBRTC_VIDEO_ENGINE_ENCRYPTION_API +#include "vie_encryption_impl.h" +#endif +#ifdef WEBRTC_VIDEO_ENGINE_FILE_API +#include "vie_file_impl.h" +#endif +#ifdef WEBRTC_VIDEO_ENGINE_IMAGE_PROCESS_API +#include "vie_image_process_impl.h" +#endif +#ifdef WEBRTC_VIDEO_ENGINE_NETWORK_API +#include "vie_network_impl.h" +#endif +#ifdef WEBRTC_VIDEO_ENGINE_RENDER_API +#include "vie_render_impl.h" +#endif +#ifdef WEBRTC_VIDEO_ENGINE_RTP_RTCP_API +#include "vie_rtp_rtcp_impl.h" +#endif +#ifdef WEBRTC_VIDEO_ENGINE_EXTERNAL_CODEC_API +#include "vie_external_codec_impl.h" +#endif + +namespace webrtc +{ + +class VideoEngineImpl: public ViEBaseImpl +#ifdef WEBRTC_VIDEO_ENGINE_CODEC_API + , public ViECodecImpl +#endif +#ifdef WEBRTC_VIDEO_ENGINE_CAPTURE_API + , public ViECaptureImpl +#endif +#ifdef WEBRTC_VIDEO_ENGINE_ENCRYPTION_API + , public ViEEncryptionImpl +#endif +#ifdef WEBRTC_VIDEO_ENGINE_FILE_API + , public ViEFileImpl +#endif +#ifdef WEBRTC_VIDEO_ENGINE_IMAGE_PROCESS_API + , public ViEImageProcessImpl +#endif +#ifdef WEBRTC_VIDEO_ENGINE_NETWORK_API + , public ViENetworkImpl +#endif +#ifdef WEBRTC_VIDEO_ENGINE_RENDER_API + , public ViERenderImpl +#endif +#ifdef WEBRTC_VIDEO_ENGINE_RTP_RTCP_API + , public ViERTP_RTCPImpl +#endif +#ifdef WEBRTC_VIDEO_ENGINE_EXTERNAL_CODEC_API +,public ViEExternalCodecImpl +#endif +{ +public: + VideoEngineImpl() {}; + virtual ~VideoEngineImpl() {}; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_IMPL_H_ diff --git a/video_engine/main/source/vie_input_manager.cc b/video_engine/main/source/vie_input_manager.cc new file mode 100644 index 0000000000..3f7a2607a4 --- /dev/null +++ b/video_engine/main/source/vie_input_manager.cc @@ -0,0 +1,817 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_input_manager.cc + */ + +#include "vie_input_manager.h" +#include "vie_defines.h" + +#include "common_types.h" +#include "critical_section_wrapper.h" +#include "video_capture.h" +#include "video_capture.h" +#include "video_coding.h" +#include "video_coding_defines.h" +#include "rw_lock_wrapper.h" +#include "trace.h" +#include "vie_capturer.h" +#include "vie_file_player.h" +#include "vie_errors.h" + +#include + +namespace webrtc { + +//============================================================================= +// ViEInputManager +//============================================================================= + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViEInputManager::ViEInputManager(const int engineId) + : _engineId(engineId), + _mapCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _ptrCaptureDeviceInfo(NULL), _vieFrameProviderMap(), + _freeCaptureDeviceId(), _moduleProcessThread(NULL) +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(_engineId), "%s", + __FUNCTION__); + + for (int idx = 0; idx < kViEMaxCaptureDevices; idx++) + { + _freeCaptureDeviceId[idx] = true; + } +#ifdef WEBRTC_VIDEO_EXTERNAL_CAPTURE_AND_RENDER + _ptrCaptureDeviceInfo=NULL; +#else + _ptrCaptureDeviceInfo = VideoCaptureModule::CreateDeviceInfo( + ViEModuleId(_engineId)); +#endif + for (int idx = 0; idx < kViEMaxFilePlayers; idx++) + { + _freeFileId[idx] = true; + } + +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViEInputManager::~ViEInputManager() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(_engineId), "%s", + __FUNCTION__); + while (_vieFrameProviderMap.Size() != 0) + { + MapItem* item = _vieFrameProviderMap.First(); + assert(item); + ViEFrameProviderBase* frameProvider = static_cast + (item->GetItem()); + _vieFrameProviderMap.Erase(item); + delete frameProvider; + } + + delete &_mapCritsect; + if (_ptrCaptureDeviceInfo) + { + VideoCaptureModule::DestroyDeviceInfo( _ptrCaptureDeviceInfo); + _ptrCaptureDeviceInfo = NULL; + } +} + +// ---------------------------------------------------------------------------- +// SetModuleProcessThread +// Initialize the thread context used by none time critical tasks in capture modules. +// ---------------------------------------------------------------------------- +void ViEInputManager::SetModuleProcessThread(ProcessThread& moduleProcessThread) +{ + assert(!_moduleProcessThread); + _moduleProcessThread = &moduleProcessThread; +} +// ---------------------------------------------------------------------------- +// NumberOfCaptureDevices +// +// Returns the number of available capture devices +// ---------------------------------------------------------------------------- + +// Capture device information +int ViEInputManager::NumberOfCaptureDevices() +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s", + __FUNCTION__); + assert(_ptrCaptureDeviceInfo); + return _ptrCaptureDeviceInfo->NumberOfDevices(); +} + +// ---------------------------------------------------------------------------- +// GetDeviceName +// ---------------------------------------------------------------------------- + +int ViEInputManager::GetDeviceName(WebRtc_UWord32 deviceNumber, + WebRtc_UWord8* deviceNameUTF8, + WebRtc_UWord32 deviceNameLength, + WebRtc_UWord8* deviceUniqueIdUTF8, + WebRtc_UWord32 deviceUniqueIdUTF8Length) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s(deviceNumber: %d)", __FUNCTION__, deviceNumber); + assert(_ptrCaptureDeviceInfo); + return _ptrCaptureDeviceInfo->GetDeviceName(deviceNumber, deviceNameUTF8, + deviceNameLength, + deviceUniqueIdUTF8, + deviceUniqueIdUTF8Length); +} + +// ---------------------------------------------------------------------------- +// NumberOfCaptureCapabilities +// +// Returns the number of capture capabilities for the specified capture device +// ---------------------------------------------------------------------------- + +int ViEInputManager::NumberOfCaptureCapabilities( + const WebRtc_UWord8* deviceUniqueIdUTF8) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s", + __FUNCTION__); + assert(_ptrCaptureDeviceInfo); + return _ptrCaptureDeviceInfo->NumberOfCapabilities(deviceUniqueIdUTF8); +} + +// ---------------------------------------------------------------------------- +// GetCaptureCapability +// ---------------------------------------------------------------------------- + +int ViEInputManager::GetCaptureCapability(const WebRtc_UWord8* deviceUniqueIdUTF8, + const WebRtc_UWord32 deviceCapabilityNumber, + CaptureCapability& capability) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s(deviceUniqueIdUTF8: %s, deviceCapabilityNumber: %d)", + __FUNCTION__, deviceUniqueIdUTF8, deviceCapabilityNumber); + assert(_ptrCaptureDeviceInfo); + VideoCaptureCapability moduleCapability; + int result = _ptrCaptureDeviceInfo->GetCapability(deviceUniqueIdUTF8, + deviceCapabilityNumber, + moduleCapability); + // Copy from module type to public type + capability.expectedCaptureDelay = moduleCapability.expectedCaptureDelay; + capability.height = moduleCapability.height; + capability.width = moduleCapability.width; + capability.interlaced = moduleCapability.interlaced; + capability.rawType = moduleCapability.rawType; + capability.codecType = moduleCapability.codecType; + capability.maxFPS = moduleCapability.maxFPS; + return result; +} + +int ViEInputManager::GetOrientation(const WebRtc_UWord8* deviceUniqueIdUTF8, + RotateCapturedFrame &orientation) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s(deviceUniqueIdUTF8: %s,)", __FUNCTION__, deviceUniqueIdUTF8); + assert(_ptrCaptureDeviceInfo); + VideoCaptureRotation moduleOrientation; + int result = _ptrCaptureDeviceInfo->GetOrientation(deviceUniqueIdUTF8, + moduleOrientation); + // Copy from module type to public type + switch (moduleOrientation) + { + case kCameraRotate0: + orientation = RotateCapturedFrame_0; + break; + case kCameraRotate90: + orientation = RotateCapturedFrame_90; + break; + case kCameraRotate180: + orientation = RotateCapturedFrame_180; + break; + case kCameraRotate270: + orientation = RotateCapturedFrame_270; + break; + default: + assert(!"Unknown enum"); + } + return result; +} + +//------------------------------------------------------------------------------ +// +// DisplayCaptureSettingsDialogBox +// Show OS specific Capture settings. +// Return 0 on success. +//------------------------------------------------------------------------------ +int ViEInputManager::DisplayCaptureSettingsDialogBox( + const WebRtc_UWord8* deviceUniqueIdUTF8, + const WebRtc_UWord8* dialogTitleUTF8, + void* parentWindow, + WebRtc_UWord32 positionX, + WebRtc_UWord32 positionY) +{ + assert(_ptrCaptureDeviceInfo); + return _ptrCaptureDeviceInfo->DisplayCaptureSettingsDialogBox( + deviceUniqueIdUTF8, + dialogTitleUTF8, + parentWindow, + positionX, + positionY); +} +// ---------------------------------------------------------------------------- +// CreateCaptureDevice +// +// Creates a capture module for the specified capture device and assigns +// a capture device id for the device +// ---------------------------------------------------------------------------- + +int ViEInputManager::CreateCaptureDevice(const WebRtc_UWord8* deviceUniqueIdUTF8, + const WebRtc_UWord32 deviceUniqueIdUTF8Length, + int& captureId) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s(deviceUniqueId: %s)", __FUNCTION__, deviceUniqueIdUTF8); +#ifdef WEBRTC_VIDEO_EXTERNAL_CAPTURE_AND_RENDER + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s(deviceUniqueId: Only external capture modules can be used.) " + , __FUNCTION__); + return -1; +#endif + CriticalSectionScoped cs(_mapCritsect); + + // Make sure the device is not already allocated + for (MapItem* item = _vieFrameProviderMap.First(); item != NULL; + item = _vieFrameProviderMap.Next(item)) + { + if (item->GetId() >= kViECaptureIdBase && + item->GetId() <= kViECaptureIdMax) // Make sure it is a capture device + { + ViECapturer* vieCapture = static_cast (item->GetItem()); + assert(vieCapture); + if (strncmp((char*) vieCapture->CurrentDeviceName(), + (char*) deviceUniqueIdUTF8, + strlen((char*) vieCapture->CurrentDeviceName())) == 0) + { + return kViECaptureDeviceAlreadyAllocated; + } + } + } + + // Make sure the device name is valid + bool foundDevice = false; + for (WebRtc_UWord32 deviceIndex = 0; + deviceIndex < _ptrCaptureDeviceInfo->NumberOfDevices(); ++deviceIndex) + { + if (deviceUniqueIdUTF8Length >kVideoCaptureUniqueNameLength) + { + // user's string length is longer than the max + return -1; + } + + WebRtc_UWord8 foundName[kVideoCaptureDeviceNameLength] = ""; + WebRtc_UWord8 foundUniqueName[kVideoCaptureUniqueNameLength] = ""; + _ptrCaptureDeviceInfo->GetDeviceName(deviceIndex, foundName, + kVideoCaptureDeviceNameLength, + foundUniqueName, + kVideoCaptureUniqueNameLength); + + if (strncmp((char*) deviceUniqueIdUTF8, (char*) foundUniqueName, + strlen((char*) deviceUniqueIdUTF8)) == 0) + { + WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo, ViEId(_engineId), + "%s:%d Capture device was found by unique ID: %s. Returning", + __FUNCTION__, __LINE__, deviceUniqueIdUTF8); + foundDevice = true; + break; + } + } + if (!foundDevice) + { + WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo, ViEId(_engineId), + "%s:%d Capture device NOT found by unique ID: %s. Returning", + __FUNCTION__, __LINE__, deviceUniqueIdUTF8); + return kViECaptureDeviceDoesnNotExist; + } + + int newcaptureId = 0; + if (GetFreeCaptureId(newcaptureId) == false) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Maximum supported number of capture devices already in use", + __FUNCTION__); + return kViECaptureDeviceMaxNoDevicesAllocated; + } + ViECapturer* vieCapture =ViECapturer::CreateViECapture(newcaptureId, + _engineId, + deviceUniqueIdUTF8, + deviceUniqueIdUTF8Length, + *_moduleProcessThread); + if (vieCapture == NULL) + { + ReturnCaptureId(newcaptureId); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could not create capture module for %s", __FUNCTION__, + deviceUniqueIdUTF8); + return kViECaptureDeviceUnknownError; + } + + if (_vieFrameProviderMap.Insert(newcaptureId, vieCapture) != 0) + { + ReturnCaptureId(newcaptureId); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could not insert capture module for %s", __FUNCTION__, + deviceUniqueIdUTF8); + return kViECaptureDeviceUnknownError; + } + captureId = newcaptureId; + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s(deviceUniqueId: %s, captureId: %d)", __FUNCTION__, + deviceUniqueIdUTF8, captureId); + + return 0; +} + +int ViEInputManager::CreateCaptureDevice(VideoCaptureModule& captureModule, + int& captureId) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s", __FUNCTION__); + + CriticalSectionScoped cs(_mapCritsect); + + int newcaptureId = 0; + if (GetFreeCaptureId(newcaptureId) == false) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Maximum supported number of capture devices already in use", + __FUNCTION__); + return kViECaptureDeviceMaxNoDevicesAllocated; + } + + ViECapturer* vieCapture = ViECapturer::CreateViECapture(newcaptureId, + _engineId, + captureModule, + *_moduleProcessThread); + if (vieCapture == NULL) + { + ReturnCaptureId(newcaptureId); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could attach capture module.", __FUNCTION__); + return kViECaptureDeviceUnknownError; + } + if (_vieFrameProviderMap.Insert(newcaptureId, vieCapture) != 0) + { + ReturnCaptureId(newcaptureId); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could not insert capture module", __FUNCTION__); + return kViECaptureDeviceUnknownError; + } + + captureId = newcaptureId; + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s, captureId: %d", __FUNCTION__, captureId); + + return 0; + +} + +// ---------------------------------------------------------------------------- +// DestroyCaptureDevice +// +// Releases the capture device with specified id +// ---------------------------------------------------------------------------- + +int ViEInputManager::DestroyCaptureDevice(const int captureId) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s(captureId: %d)", __FUNCTION__, captureId); + + ViECapturer* vieCapture = NULL; + { + // We need exclusive access to the object to delete it + ViEManagerWriteScoped wl(*this); // Take this write lock first since the read lock is taken before _mapCritsect + CriticalSectionScoped cs(_mapCritsect); + + vieCapture = ViECapturePtr(captureId); + if (vieCapture == NULL) + { + // No capture deveice with that id + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s(captureId: %d) - No such capture device id", + __FUNCTION__, captureId); + return -1; + } + WebRtc_UWord32 numCallbacks = vieCapture->NumberOfRegistersFrameCallbacks(); + if (numCallbacks > 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId), + "%s(captureId: %d) - %u registered callbacks when destroying capture device", + __FUNCTION__, captureId, numCallbacks); + } + _vieFrameProviderMap.Erase(captureId); + ReturnCaptureId(captureId); + } // Leave cs before deleting the capture object. This is because deleting the object might cause deletions of renderers so we prefer to not have a lock at that time. + delete vieCapture; + return 0; +} +// ---------------------------------------------------------------------------- +// CreateExternalCaptureDevice +// +// Creates a capture module to be used with external captureing. +// ---------------------------------------------------------------------------- +int ViEInputManager::CreateExternalCaptureDevice(ViEExternalCapture*& externalCapture, + int& captureId) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s", + __FUNCTION__); +#ifdef WEBRTC_VIDEO_EXTERNAL_CAPTURE_AND_RENDER + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s(deviceUniqueId: Only external capture modules can be used.) " + , __FUNCTION__); + return -1; +#endif + CriticalSectionScoped cs(_mapCritsect); + + int newcaptureId = 0; + if (GetFreeCaptureId(newcaptureId) == false) + { + WEBRTC_TRACE( webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Maximum supported number of capture devices already in use", + __FUNCTION__); + return kViECaptureDeviceMaxNoDevicesAllocated; + } + + ViECapturer* vieCapture = ViECapturer::CreateViECapture(newcaptureId, + _engineId, NULL, 0, + *_moduleProcessThread); + if (vieCapture == NULL) + { + ReturnCaptureId(newcaptureId); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could not create capture module for external capture.", + __FUNCTION__); + return kViECaptureDeviceUnknownError; + } + + if (_vieFrameProviderMap.Insert(newcaptureId, vieCapture) != 0) + { + ReturnCaptureId(newcaptureId); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could not insert capture module for external capture.", + __FUNCTION__); + return kViECaptureDeviceUnknownError; + } + captureId = newcaptureId; + externalCapture = vieCapture; + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s, captureId: %d)", __FUNCTION__, captureId); + return 0; +} + +int ViEInputManager::CreateFilePlayer(const WebRtc_Word8* fileNameUTF8, + const bool loop, + const webrtc::FileFormats fileFormat, + VoiceEngine* vePtr, int& fileId) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s(deviceUniqueId: %s)", __FUNCTION__, fileNameUTF8); + + CriticalSectionScoped cs(_mapCritsect); + + int newFileId = 0; + if (GetFreeFileId(newFileId) == false) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Maximum supported number of file players already in use", + __FUNCTION__); + return kViEFileMaxNoOfFilesOpened; + } + + ViEFilePlayer* vieFilePlayer = ViEFilePlayer::CreateViEFilePlayer( + newFileId, _engineId, fileNameUTF8, + loop, fileFormat, *this, vePtr); + if (vieFilePlayer == NULL) + { + ReturnFileId(newFileId); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could not open file %s for playback", __FUNCTION__, + fileNameUTF8); + return kViEFileUnknownError; + } + + if (_vieFrameProviderMap.Insert(newFileId, vieFilePlayer) != 0) + { + ReturnCaptureId(newFileId); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could not insert file player for %s", __FUNCTION__, + fileNameUTF8); + delete vieFilePlayer; + return kViEFileUnknownError; + } + + fileId = newFileId; + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s(filename: %s, fileId: %d)", __FUNCTION__, fileNameUTF8, + newFileId); + return 0; +} + +int ViEInputManager::DestroyFilePlayer(int fileId) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s(fileId: %d)", __FUNCTION__, fileId); + + ViEFilePlayer* vieFilePlayer = NULL; + { + // We need exclusive access to the object to delete it + ViEManagerWriteScoped wl(*this); // Take this write lock first since the read lock is taken before _mapCritsect + + CriticalSectionScoped cs(_mapCritsect); + + vieFilePlayer = ViEFilePlayerPtr(fileId); + if (vieFilePlayer == NULL) + { + // No capture deveice with that id + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s(fileId: %d) - No such file player", + __FUNCTION__, fileId); + + return -1; + } + int numCallbacks = + vieFilePlayer->NumberOfRegistersFrameCallbacks(); + if (numCallbacks > 0) + { + WEBRTC_TRACE( webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId), + "%s(fileId: %d) - %u registered callbacks when destroying file player", + __FUNCTION__, fileId, numCallbacks); + } + _vieFrameProviderMap.Erase(fileId); + ReturnFileId(fileId); + } // Leave cs before deleting the file object. This is because deleting the object might cause deletions of renderers so we prefer to not have a lock at that time. + delete vieFilePlayer; + return 0; +} + +// ============================================================================ +// Private methods +// ============================================================================ + +// ---------------------------------------------------------------------------- +// GetFreeCaptureId +// +// Gets and allocates a free capture device id. Assumed protected by caller +// ---------------------------------------------------------------------------- + +// Private, asummed protected +bool ViEInputManager::GetFreeCaptureId(int& freecaptureId) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s", + __FUNCTION__); + + for (int id = 0; id < kViEMaxCaptureDevices; id++) + { + if (_freeCaptureDeviceId[id]) + { + // We found a free capture device id + _freeCaptureDeviceId[id] = false; + freecaptureId = id + kViECaptureIdBase; + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s: new id: %d", __FUNCTION__, freecaptureId); + return true; + } + } + return false; +} + +// ---------------------------------------------------------------------------- +// ReturnCaptureId +// +// Frees a capture id assigned in GetFreeCaptureId +// ---------------------------------------------------------------------------- + +void ViEInputManager::ReturnCaptureId(int captureId) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s(%d)", + __FUNCTION__, captureId); + + CriticalSectionScoped cs(_mapCritsect); + if (captureId >= kViECaptureIdBase && + captureId < kViEMaxCaptureDevices + kViECaptureIdBase) + { + _freeCaptureDeviceId[captureId - kViECaptureIdBase] = true; + } + + return; +} + +// ---------------------------------------------------------------------------- +// GetFreeFileId +// +// Gets and allocates a free file id. Assumed protected by caller +// ---------------------------------------------------------------------------- + +// Private, asumed protected +bool ViEInputManager::GetFreeFileId(int& freeFileId) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s", + __FUNCTION__); + + for (int id = 0; id < kViEMaxFilePlayers; id++) + { + if (_freeFileId[id]) + { + // We found a free capture device id + _freeFileId[id] = false; + freeFileId = id + kViEFileIdBase; + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s: new id: %d", __FUNCTION__, freeFileId); + return true; + } + } + return false; +} +// ---------------------------------------------------------------------------- +// ReturnFileId +// +// Frees a file id assigned in GetFreeFileId +// ---------------------------------------------------------------------------- +void ViEInputManager::ReturnFileId(int fileId) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s(%d)", + __FUNCTION__, fileId); + + CriticalSectionScoped cs(_mapCritsect); + if (fileId >= kViEFileIdBase && + fileId < kViEMaxFilePlayers + kViEFileIdBase) + { + _freeFileId[fileId - kViEFileIdBase] = true; + } + return; +} + +// ============================================================================ +// Methods used by ViECaptureScoped + +// ---------------------------------------------------------------------------- +// ViECapturePtr +// +// Gets the ViECapturer for the capture device id +// ---------------------------------------------------------------------------- + +ViECapturer* ViEInputManager::ViECapturePtr(int captureId) const +{ + if (!(captureId >= kViECaptureIdBase && + captureId <= kViECaptureIdBase + kViEMaxCaptureDevices)) + return NULL; + + CriticalSectionScoped cs(_mapCritsect); + MapItem* mapItem = _vieFrameProviderMap.Find(captureId); + if (mapItem == NULL) + { + // No ViEEncoder for this channel... + return NULL; + } + ViECapturer* vieCapture = static_cast (mapItem->GetItem()); + return vieCapture; +} + +// ---------------------------------------------------------------------------- +// ViEFrameProvider +// +// Gets the ViEFrameProvider for this capture observer. +// ---------------------------------------------------------------------------- + +ViEFrameProviderBase* ViEInputManager::ViEFrameProvider( + const ViEFrameCallback* captureObserver) const +{ + + assert(captureObserver); + CriticalSectionScoped cs(_mapCritsect); + + for (MapItem* providerItem = _vieFrameProviderMap.First(); providerItem + != NULL; providerItem = _vieFrameProviderMap.Next(providerItem)) + { + ViEFrameProviderBase* vieFrameProvider = static_cast + (providerItem->GetItem()); + assert(vieFrameProvider != NULL); + + if (vieFrameProvider->IsFrameCallbackRegistered(captureObserver)) + { + // We found it + return vieFrameProvider; + } + } + // No capture device set for this channel + return NULL; +} + +// ---------------------------------------------------------------------------- +// ViEFrameProvider +// +// Gets the ViEFrameProvider for this capture observer. +// ---------------------------------------------------------------------------- + +ViEFrameProviderBase* ViEInputManager::ViEFrameProvider(int providerId) const +{ + CriticalSectionScoped cs(_mapCritsect); + MapItem* mapItem = _vieFrameProviderMap.Find(providerId); + if (mapItem == NULL) + { + return NULL; + } + + ViEFrameProviderBase* vieFrameProvider = static_cast + (mapItem->GetItem()); + return vieFrameProvider; +} + +// ---------------------------------------------------------------------------- +// GetViECaptures +// +// Gets the the entire map with GetViECaptures +// ---------------------------------------------------------------------------- +void ViEInputManager::GetViECaptures(MapWrapper& vieCaptureMap) +{ + CriticalSectionScoped cs(_mapCritsect); + + if (_vieFrameProviderMap.Size() == 0) + { + // No ViECaptures + return; + } + // Add all items to the map + for (MapItem* item = _vieFrameProviderMap.First(); + item != NULL; + item = _vieFrameProviderMap.Next(item)) + { + vieCaptureMap.Insert(item->GetId(), item->GetItem()); + } + return; +} + +// ---------------------------------------------------------------------------- +// ViEFilePlayerPtr +// +// Gets the ViEFilePlayer for this fileId +// ---------------------------------------------------------------------------- + +ViEFilePlayer* ViEInputManager::ViEFilePlayerPtr(int fileId) const +{ + if (fileId < kViEFileIdBase || fileId > kViEFileIdMax) + return NULL; + + CriticalSectionScoped cs(_mapCritsect); + MapItem* mapItem = _vieFrameProviderMap.Find(fileId); + if (mapItem == NULL) + { + // No ViEFilePlayer for this fileId... + return NULL; + } + ViEFilePlayer* vieFilePlayer = + static_cast (mapItem->GetItem()); + return vieFilePlayer; +} + +// ---------------------------------------------------------------------------- +// ViEInputManagerScoped +// +// Provides protected access to ViEInputManater +// ---------------------------------------------------------------------------- +ViEInputManagerScoped::ViEInputManagerScoped( + const ViEInputManager& vieInputManager) + : ViEManagerScopedBase(vieInputManager) +{ +} +ViECapturer* ViEInputManagerScoped::Capture(int captureId) const +{ + return static_cast + (_vieManager)->ViECapturePtr(captureId); +} +ViEFrameProviderBase* ViEInputManagerScoped::FrameProvider( + const ViEFrameCallback* captureObserver) const +{ + return static_cast + (_vieManager)->ViEFrameProvider(captureObserver); +} +ViEFrameProviderBase* ViEInputManagerScoped::FrameProvider(int providerId) const +{ + return static_cast + (_vieManager)->ViEFrameProvider( providerId); +} + +ViEFilePlayer* ViEInputManagerScoped::FilePlayer(int fileId) const +{ + return static_cast + (_vieManager)->ViEFilePlayerPtr(fileId); +} + +} // namespace webrtc diff --git a/video_engine/main/source/vie_input_manager.h b/video_engine/main/source/vie_input_manager.h new file mode 100644 index 0000000000..ec4a81a48c --- /dev/null +++ b/video_engine/main/source/vie_input_manager.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_input_manager.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_INPUT_MANAGER_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_INPUT_MANAGER_H_ + +#include "vie_defines.h" +#include "typedefs.h" +#include "map_wrapper.h" +#include "video_capture.h" +#include "vie_manager_base.h" +#include "vie_frame_provider_base.h" +#include "vie_capture.h" + +class ViEExternalCapture; + +namespace webrtc { +class CriticalSectionWrapper; +class ProcessThread; +class RWLockWrapper; +class ViECapturer; +class ViEFilePlayer; +class VoiceEngine; + +class ViEInputManager: private ViEManagerBase +{ + friend class ViEInputManagerScoped; +public: + ViEInputManager(int engineId); + ~ViEInputManager(); + + void SetModuleProcessThread(ProcessThread& moduleProcessThread); + + // Capture device information + int NumberOfCaptureDevices(); + int GetDeviceName(WebRtc_UWord32 deviceNumber, + WebRtc_UWord8* deviceNameUTF8, + WebRtc_UWord32 deviceNameLength, + WebRtc_UWord8* deviceUniqueIdUTF8, + WebRtc_UWord32 deviceUniqueIdUTF8Length); + int NumberOfCaptureCapabilities(const WebRtc_UWord8* deviceUniqueIdUTF8); + int GetCaptureCapability(const WebRtc_UWord8* deviceUniqueIdUTF8, + const WebRtc_UWord32 deviceCapabilityNumber, + CaptureCapability& capability); + int DisplayCaptureSettingsDialogBox(const WebRtc_UWord8* deviceUniqueIdUTF8, + const WebRtc_UWord8* dialogTitleUTF8, + void* parentWindow, + WebRtc_UWord32 positionX, + WebRtc_UWord32 positionY); + int GetOrientation(const WebRtc_UWord8* deviceUniqueIdUTF8, + RotateCapturedFrame &orientation); + + // Create/delete Capture device settings + // Return zero on success. A ViEError on failure. + int CreateCaptureDevice(const WebRtc_UWord8* deviceUniqueIdUTF8, + const WebRtc_UWord32 deviceUniqueIdUTF8Length, + int& captureId); + int CreateCaptureDevice(VideoCaptureModule& captureModule, + int& captureId); + int CreateExternalCaptureDevice(ViEExternalCapture*& externalCapture, + int& captureId); + int DestroyCaptureDevice(int captureId); + + int CreateFilePlayer(const WebRtc_Word8* fileNameUTF8, const bool loop, + const webrtc::FileFormats fileFormat, VoiceEngine* vePtr, + int& fileId); + int DestroyFilePlayer(int fileId); + +private: + bool GetFreeCaptureId(int& freecaptureId); + void ReturnCaptureId(int captureId); + bool GetFreeFileId(int& freeFileId); + void ReturnFileId(int fileId); + + ViEFrameProviderBase* ViEFrameProvider(const ViEFrameCallback* + captureObserver) const; + ViEFrameProviderBase* ViEFrameProvider(int providerId) const; + + ViECapturer* ViECapturePtr(int captureId) const; + void GetViECaptures(MapWrapper& vieCaptureMap); + + ViEFilePlayer* ViEFilePlayerPtr(int fileId) const; + + // Members + int _engineId; + CriticalSectionWrapper& _mapCritsect; + MapWrapper _vieFrameProviderMap; + + // Capture devices + VideoCaptureModule::DeviceInfo* _ptrCaptureDeviceInfo; + int _freeCaptureDeviceId[kViEMaxCaptureDevices]; + //File Players + int _freeFileId[kViEMaxFilePlayers]; + //uses + ProcessThread* _moduleProcessThread; +}; + +class ViEInputManagerScoped: private ViEManagerScopedBase +{ +public: + ViEInputManagerScoped(const ViEInputManager& vieInputManager); + + ViECapturer* Capture(int captureId) const; + ViEFilePlayer* FilePlayer(int fileId) const; + ViEFrameProviderBase* FrameProvider(int providerId) const; + ViEFrameProviderBase* FrameProvider(const ViEFrameCallback* + captureObserver) const; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_INPUT_MANAGER_H_ diff --git a/video_engine/main/source/vie_manager_base.cc b/video_engine/main/source/vie_manager_base.cc new file mode 100644 index 0000000000..4d36a16c53 --- /dev/null +++ b/video_engine/main/source/vie_manager_base.cc @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vie_manager_base.h" +#include "rw_lock_wrapper.h" +#include "assert.h" + +namespace webrtc { + +ViEManagerBase::ViEManagerBase() : + _instanceRWLock(*RWLockWrapper::CreateRWLock()) +{ +} +ViEManagerBase::~ViEManagerBase() +{ + delete &_instanceRWLock; +} + +// ---------------------------------------------------------------------------- +// ReadLockManager +// +// Lock count increase. Used by ViEManagerScopedBase +// ---------------------------------------------------------------------------- +void ViEManagerBase::ReadLockManager() const +{ + _instanceRWLock.AcquireLockShared(); +} + +// ---------------------------------------------------------------------------- +// ReleaseLockManager +// +// Releases the lock count. +// ---------------------------------------------------------------------------- +void ViEManagerBase::ReleaseLockManager() const +{ + _instanceRWLock.ReleaseLockShared(); +} + +// ---------------------------------------------------------------------------- +// WriteLockManager +// +// Lock count increase. Used by ViEManagerWriteScoped +// ---------------------------------------------------------------------------- +void ViEManagerBase::WriteLockManager() +{ + _instanceRWLock.AcquireLockExclusive(); +} + +// ---------------------------------------------------------------------------- +// ReleaseLockManager +// +// Releases the lock count. +// ---------------------------------------------------------------------------- +void ViEManagerBase::ReleaseWriteLockManager() +{ + _instanceRWLock.ReleaseLockExclusive(); +} + +// ---------------------------------------------------------------------------- +// ViEManagerScopedBase +// +// ---------------------------------------------------------------------------- +ViEManagerScopedBase::ViEManagerScopedBase(const ViEManagerBase& ViEManagerBase) : + _vieManager(&ViEManagerBase), _refCount(0) +{ + _vieManager->ReadLockManager(); +} + +ViEManagerScopedBase::~ViEManagerScopedBase() +{ + assert(_refCount==0); + _vieManager->ReleaseLockManager(); +} + +// ---------------------------------------------------------------------------- +/// +// ViEManagerWriteScoped +// +// ---------------------------------------------------------------------------- +ViEManagerWriteScoped::ViEManagerWriteScoped(ViEManagerBase& vieManager) : + _vieManager(&vieManager) +{ + _vieManager->WriteLockManager(); +} + +ViEManagerWriteScoped::~ViEManagerWriteScoped() +{ + _vieManager->ReleaseWriteLockManager(); +} + +// ---------------------------------------------------------------------------- +// ViEManagedItemScopedBase +// +// ---------------------------------------------------------------------------- +ViEManagedItemScopedBase::ViEManagedItemScopedBase( + ViEManagerScopedBase& vieScopedManager) : + _vieScopedManager(vieScopedManager) +{ + _vieScopedManager._refCount++; +} + +ViEManagedItemScopedBase::~ViEManagedItemScopedBase() +{ + _vieScopedManager._refCount--; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_manager_base.h b/video_engine/main/source/vie_manager_base.h new file mode 100644 index 0000000000..c70f99861b --- /dev/null +++ b/video_engine/main/source/vie_manager_base.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_MANAGER_BASE_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_MANAGER_BASE_H_ + +namespace webrtc { +class RWLockWrapper; + +class ViEManagerBase +{ + friend class ViEManagerScopedBase; + friend class ViEManagedItemScopedBase; + friend class ViEManagerWriteScoped; +public: + ViEManagerBase(void); + ~ViEManagerBase(void); +private: + void WriteLockManager(); + void ReleaseWriteLockManager(); + void ReadLockManager() const; + void ReleaseLockManager() const; + RWLockWrapper& _instanceRWLock; +}; + +class ViEManagerWriteScoped +{ +public: + ViEManagerWriteScoped(ViEManagerBase& vieManager); + ~ViEManagerWriteScoped(); +private: + ViEManagerBase* _vieManager; +}; + +class ViEManagerScopedBase +{ + friend class ViEManagedItemScopedBase; +public: + ViEManagerScopedBase(const ViEManagerBase& vieManager); + ~ViEManagerScopedBase(); +protected: + const ViEManagerBase* _vieManager; +private: + int _refCount; +}; + +class ViEManagedItemScopedBase +{ +public: + ViEManagedItemScopedBase(ViEManagerScopedBase& vieScopedManager); + ~ViEManagedItemScopedBase(); +protected: + ViEManagerScopedBase& _vieScopedManager; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_MANAGER_BASE_H_ diff --git a/video_engine/main/source/vie_network_impl.cc b/video_engine/main/source/vie_network_impl.cc new file mode 100644 index 0000000000..97be08a6bb --- /dev/null +++ b/video_engine/main/source/vie_network_impl.cc @@ -0,0 +1,1126 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_network_impl.cpp + */ + +#include "vie_network_impl.h" + +// Defines +#include "engine_configurations.h" +#include "vie_defines.h" + +// WebRTC include +#include "vie_errors.h" +#include "trace.h" +#include "vie_impl.h" +#include "vie_channel.h" +#include "vie_channel_manager.h" +#include "vie_encoder.h" + +// System include +#include + +// Conditional system include +#if (defined(_WIN32) || defined(_WIN64)) +#include +#endif + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// GetInterface +// ---------------------------------------------------------------------------- + +ViENetwork* ViENetwork::GetInterface(VideoEngine* videoEngine) +{ +#ifdef WEBRTC_VIDEO_ENGINE_NETWORK_API + if (videoEngine == NULL) + { + return NULL; + } + VideoEngineImpl* vieImpl = reinterpret_cast (videoEngine); + ViENetworkImpl* vieNetworkImpl = vieImpl; + (*vieNetworkImpl)++; // Increase ref count + + return vieNetworkImpl; +#else + return NULL; +#endif +} + +// ---------------------------------------------------------------------------- +// Release +// +// Releases the interface, i.e. reduces the reference counter. The number of +// remaining references is returned, -1 if released too many times. +// ---------------------------------------------------------------------------- + +int ViENetworkImpl::Release() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "ViENetwork::Release()"); + (*this)--; // Decrease ref count + + WebRtc_Word32 refCount = GetCount(); + if (refCount < 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, + "ViENetwork release too many times"); + SetLastError(kViEAPIDoesNotExist); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId, + "ViENetwork reference count: %d", refCount); + return refCount; +} + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViENetworkImpl::ViENetworkImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViENetworkImpl::ViENetworkImpl() Ctor"); +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViENetworkImpl::~ViENetworkImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViENetworkImpl::~ViENetworkImpl() Dtor"); +} + +// ============================================================================ +// Receive functions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetLocalReceiver +// +// Initializes the receive socket +// ---------------------------------------------------------------------------- +int ViENetworkImpl::SetLocalReceiver(const int videoChannel, + const unsigned short rtpPort, + const unsigned short rtcpPort, + const char* ipAddress) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, rtpPort: %u, rtcpPort: %u, ipAddress: %s)", + __FUNCTION__, videoChannel, rtpPort, rtcpPort, ipAddress); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId,videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + + if (ptrViEChannel->Receiving()) + { + SetLastError(kViENetworkAlreadyReceiving); + return -1; + } + if (ptrViEChannel->SetLocalReceiver(rtpPort, rtcpPort, ipAddress) != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetLocalReceiver +// +// Gets settings for an initialized receive socket +// ---------------------------------------------------------------------------- +int ViENetworkImpl::GetLocalReceiver(const int videoChannel, + unsigned short& rtpPort, + unsigned short& rtcpPort, char* ipAddress) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->GetLocalReceiver(rtpPort, rtcpPort, ipAddress) != 0) + { + SetLastError(kViENetworkLocalReceiverNotSet); + return -1; + } + return 0; +} + +// ============================================================================ +// Send functions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetSendDestination +// +// Initializes the send socket +// ---------------------------------------------------------------------------- +int ViENetworkImpl::SetSendDestination(const int videoChannel, + const char* ipAddress, + const unsigned short rtpPort, + const unsigned short rtcpPort, + const unsigned short sourceRtpPort, + const unsigned short sourceRtcpPort) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, ipAddress: x, rtpPort: %u, rtcpPort: %u, " + "sourceRtpPort: %u, sourceRtcpPort: %u)", + __FUNCTION__, rtpPort, rtcpPort, sourceRtpPort, + sourceRtcpPort); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s Channel doesn't exist", __FUNCTION__); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->Sending()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s Channel already sending.", __FUNCTION__); + SetLastError(kViENetworkAlreadySending); + return -1; + } + if (ptrViEChannel->SetSendDestination(ipAddress, rtpPort, rtcpPort, + sourceRtpPort, sourceRtcpPort) != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// GetSendDestination +// +// Gets settings for an initialized send socket +// ---------------------------------------------------------------------------- +int ViENetworkImpl::GetSendDestination(const int videoChannel, char* ipAddress, + unsigned short& rtpPort, + unsigned short& rtcpPort, + unsigned short& sourceRtpPort, + unsigned short& sourceRtcpPort) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->GetSendDestination(ipAddress, rtpPort, rtcpPort, + sourceRtpPort, sourceRtcpPort) != 0) + { + SetLastError(kViENetworkDestinationNotSet); + return -1; + } + return 0; +} + +// ============================================================================ +// External transport +// ============================================================================ + +// ---------------------------------------------------------------------------- +// RegisterSendTransport +// +// Registers the customer implemented send transport +// ---------------------------------------------------------------------------- +int ViENetworkImpl::RegisterSendTransport(const int videoChannel, + Transport& transport) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s Channel doesn't exist", __FUNCTION__); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->Sending()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s Channel already sending.", __FUNCTION__); + SetLastError(kViENetworkAlreadySending); + return -1; + } + if (ptrViEChannel->RegisterSendTransport(transport) != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterSendTransport +// +// Deregisters the send transport implementation from +// RegisterSendTransport +// ---------------------------------------------------------------------------- +int ViENetworkImpl::DeregisterSendTransport(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s Channel doesn't exist", __FUNCTION__); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->Sending()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s Channel already sending", __FUNCTION__); + SetLastError(kViENetworkAlreadySending); + return -1; + } + if (ptrViEChannel->DeregisterSendTransport() != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// ReceivedRTPPacket +// +// Function for inserting a RTP packet received by a customer transport +// ---------------------------------------------------------------------------- +int ViENetworkImpl::ReceivedRTPPacket(const int videoChannel, const void* data, + const int length) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, data: -, length: %d)", __FUNCTION__, + videoChannel, length); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + return ptrViEChannel->ReceivedRTPPacket(data, length); +} + +// ---------------------------------------------------------------------------- +// ReceivedRTCPPacket +// +// Function for inserting a RTCP packet received by a customer transport +// ---------------------------------------------------------------------------- +int ViENetworkImpl::ReceivedRTCPPacket(const int videoChannel, + const void* data, const int length) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, data: -, length: %d)", __FUNCTION__, + videoChannel, length); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + return ptrViEChannel->ReceivedRTCPPacket(data, length); +} + +// ============================================================================ +// Get info +// ============================================================================ + +// ---------------------------------------------------------------------------- +// GetSourceInfo +// +// Retreives informatino about the remote side sockets +// ---------------------------------------------------------------------------- +int ViENetworkImpl::GetSourceInfo(const int videoChannel, + unsigned short& rtpPort, + unsigned short& rtcpPort, char* ipAddress, + unsigned int ipAddressLength) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->GetSourceInfo(rtpPort, rtcpPort, ipAddress, + ipAddressLength) != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetLocalIP +// +// Gets the local ip address +// ---------------------------------------------------------------------------- +int ViENetworkImpl::GetLocalIP(char ipAddress[64], bool ipv6) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s( ipAddress, ipV6: %d)", __FUNCTION__, ipv6); + +#ifndef WEBRTC_EXTERNAL_TRANSPORT + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + if (ipAddress == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: No argument", __FUNCTION__); + SetLastError(kViENetworkInvalidArgument); + return -1; + } + + WebRtc_UWord8 numSocketThreads = 1; + UdpTransport* ptrSocketTransport = + UdpTransport::Create( + ViEModuleId(_instanceId,-1),numSocketThreads); + + if (ptrSocketTransport == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Could not create socket module", __FUNCTION__); + SetLastError(kViENetworkUnknownError); + return -1; + } + + WebRtc_Word8 localIpAddress[64]; + if (ipv6) + { + WebRtc_UWord8 localIP[16]; + if (ptrSocketTransport->LocalHostAddressIPV6(localIP) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Could not get local IP", __FUNCTION__); + SetLastError(kViENetworkUnknownError); + return -1; + } + // Convert 128-bit address to character string (a:b:c:d:e:f:g:h) + sprintf(localIpAddress, + "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", + localIP[0], localIP[1], localIP[2], localIP[3], localIP[4], + localIP[5], localIP[6], localIP[7], localIP[8], localIP[9], + localIP[10], localIP[11], localIP[12], localIP[13], + localIP[14], localIP[15]); + } + else + { + WebRtc_UWord32 localIP = 0; + if (ptrSocketTransport->LocalHostAddress(localIP) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: Could not get local IP", __FUNCTION__); + SetLastError(kViENetworkUnknownError); + return -1; + } + // Convert 32-bit address to character string (x.y.z.w) + sprintf(localIpAddress, "%d.%d.%d.%d", (int) ((localIP >> 24) & 0x0ff), + (int) ((localIP >> 16) & 0x0ff), + (int) ((localIP >> 8) & 0x0ff), (int) (localIP & 0x0ff)); + } + strcpy(ipAddress, localIpAddress); + UdpTransport::Destroy( + ptrSocketTransport); + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: local ip = %s", __FUNCTION__, localIpAddress); + + return 0; +#else + WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: not available for external transport", __FUNCTION__); + + return -1; +#endif +} + +// ============================================================================ +// IPv6 +// ============================================================================ + +// ---------------------------------------------------------------------------- +// EnableIPv6 +// +// Enables IPv6 +// ---------------------------------------------------------------------------- +int ViENetworkImpl::EnableIPv6(int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->EnableIPv6() != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// IsIPv6Enabled +// +// Returns true if IPv6 is enabled, false otherwise. +// ---------------------------------------------------------------------------- +bool ViENetworkImpl::IsIPv6Enabled(int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return false; + } + return ptrViEChannel->IsIPv6Enabled(); +} + +// ============================================================================ +// Source IP address and port filter +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetSourceFilter +// +// Sets filter source port and IP address. Packets from all other sources +// will be discarded. +// ---------------------------------------------------------------------------- +int ViENetworkImpl::SetSourceFilter(const int videoChannel, + const unsigned short rtpPort, + const unsigned short rtcpPort, + const char* ipAddress) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, rtpPort: %u, rtcpPort: %u, ipAddress: %s)", + __FUNCTION__, videoChannel, rtpPort, rtcpPort, ipAddress); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->SetSourceFilter(rtpPort, rtcpPort, ipAddress) != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetSourceFilter +// +// Gets vaules set by SetSourceFilter +// ---------------------------------------------------------------------------- +int ViENetworkImpl::GetSourceFilter(const int videoChannel, + unsigned short& rtpPort, + unsigned short& rtcpPort, char* ipAddress) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->GetSourceFilter(rtpPort, rtcpPort, ipAddress) != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// ToS +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetToS +// +// Sets values for ToS +// ---------------------------------------------------------------------------- +int ViENetworkImpl::SetSendToS(const int videoChannel, const int DSCP, + const bool useSetSockOpt = false) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, DSCP: %d, useSetSockOpt: %d)", __FUNCTION__, + videoChannel, DSCP, useSetSockOpt); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + +#if defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(_instanceId, videoChannel), + " force useSetSockopt=true since there is no alternative" + " implementation"); + if (ptrViEChannel->SetToS(DSCP, true) != 0) +#else + if (ptrViEChannel->SetToS(DSCP, useSetSockOpt) != 0) +#endif + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetToS +// +// Gets values set by SetToS +// ---------------------------------------------------------------------------- +int ViENetworkImpl::GetSendToS(const int videoChannel, int& DSCP, + bool& useSetSockOpt) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->GetToS((WebRtc_Word32&) DSCP, useSetSockOpt) != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// GQoS +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetSendGQoS +// +// Sets settings for GQoS. Must be called after SetSendCodec to get correct +// bitrate setting. +// ---------------------------------------------------------------------------- +int ViENetworkImpl::SetSendGQoS(const int videoChannel, const bool enable, + const int serviceType, const int overrideDSCP) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, enable: %d, serviceType: %d, " + "overrideDSCP: %d)", + __FUNCTION__, videoChannel, enable, serviceType, overrideDSCP); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + +#if (defined(_WIN32) || defined(_WIN64)) + // Sanity check. We might crash if testing and relying on an OS socket error + if (enable + && (serviceType != SERVICETYPE_BESTEFFORT) + && (serviceType != SERVICETYPE_CONTROLLEDLOAD) + && (serviceType != SERVICETYPE_GUARANTEED) && + (serviceType != SERVICETYPE_QUALITATIVE)) + { + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: service type %d not supported", __FUNCTION__, + videoChannel, serviceType); + SetLastError(kViENetworkServiceTypeNotSupported); + return -1; + } + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + ViEEncoder* ptrVieEncoder = cs.Encoder(videoChannel); + if (ptrVieEncoder == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + VideoCodec videoCodec; + if (ptrVieEncoder->GetEncoder(videoCodec) != 0) + { + // Could not get + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Could not get max bitrate for the channel", + __FUNCTION__); + SetLastError(kViENetworkSendCodecNotSet); + return -1; + } + if(ptrViEChannel->SetSendGQoS(enable, serviceType, videoCodec.maxBitrate, + overrideDSCP)!=0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; + +#else + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s: Not supported", + __FUNCTION__); + SetLastError(kViENetworkNotSupported); + return -1; +#endif +} + +// ---------------------------------------------------------------------------- +// GetSendGQoS +// +// Gets the settigns set by SetSendGQoS +// ---------------------------------------------------------------------------- +int ViENetworkImpl::GetSendGQoS(const int videoChannel, bool& enabled, + int& serviceType, int& overrideDSCP) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->GetSendGQoS(enabled, (WebRtc_Word32&) serviceType, + (WebRtc_Word32&) overrideDSCP) != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; + +} + +// ============================================================================ +// Network settings +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetMTU +// ---------------------------------------------------------------------------- +int ViENetworkImpl::SetMTU(int videoChannel, unsigned int mtu) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d, mtu: %u)", + __FUNCTION__, videoChannel, mtu); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->SetMTU(mtu) != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; + +} + +// ============================================================================ +// Packet timout notification +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetPacketTimeoutNotification +// +// Sets the time for packet timout notifications +// ---------------------------------------------------------------------------- +int ViENetworkImpl::SetPacketTimeoutNotification(const int videoChannel, + bool enable, + int timeoutSeconds) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, enable: %d, timeoutSeconds: %u)", + __FUNCTION__, videoChannel, enable, timeoutSeconds); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->SetPacketTimeoutNotification(enable, timeoutSeconds) + != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// Periodic dead-or-alive reports +// ============================================================================ + +// ---------------------------------------------------------------------------- +// RegisterObserver +// ---------------------------------------------------------------------------- +int ViENetworkImpl::RegisterObserver(const int videoChannel, + ViENetworkObserver& observer) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->RegisterNetworkObserver(&observer) != 0) + { + SetLastError(kViENetworkObserverAlreadyRegistered); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterObserver +// ---------------------------------------------------------------------------- +int ViENetworkImpl::DeregisterObserver(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (!ptrViEChannel->NetworkObserverRegistered()) + { + SetLastError(kViENetworkObserverNotRegistered); + return -1; + } + return ptrViEChannel->RegisterNetworkObserver(NULL); +} + +// ---------------------------------------------------------------------------- +// SetPeriodicDeadOrAliveStatus +// +// Enables/disables the dead-or-alive callback +// ---------------------------------------------------------------------------- +int ViENetworkImpl::SetPeriodicDeadOrAliveStatus(const int videoChannel, + bool enable, + unsigned int sampleTimeSeconds) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, enable: %d, sampleTimeSeconds: %ul)", + __FUNCTION__, videoChannel, enable, sampleTimeSeconds); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (!ptrViEChannel->NetworkObserverRegistered()) + { + SetLastError(kViENetworkObserverNotRegistered); + return -1; + } + + if (ptrViEChannel->SetPeriodicDeadOrAliveStatus(enable, sampleTimeSeconds) + != 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// Send packet using the User Datagram Protocol (UDP) +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SendUDPPacket +// +// Send an extra UDP packet +// ---------------------------------------------------------------------------- +int ViENetworkImpl::SendUDPPacket(const int videoChannel, const void* data, + const unsigned int length, + int& transmittedBytes, + bool useRtcpSocket = false) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, data: -, length: %d, transmitterBytes: -, " + "useRtcpSocket: %d)", __FUNCTION__, videoChannel, length, + useRtcpSocket); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "Channel doesn't exist"); + SetLastError(kViENetworkInvalidChannelId); + return -1; + } + if (ptrViEChannel->SendUDPPacket((const WebRtc_Word8*) data, length, + (WebRtc_Word32&) transmittedBytes, + useRtcpSocket) < 0) + { + SetLastError(kViENetworkUnknownError); + return -1; + } + return 0; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_network_impl.h b/video_engine/main/source/vie_network_impl.h new file mode 100644 index 0000000000..41c1634ad8 --- /dev/null +++ b/video_engine/main/source/vie_network_impl.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_network_impl.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_NETWORK_IMPL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_NETWORK_IMPL_H_ + +#include "typedefs.h" +#include "vie_defines.h" +#include "vie_network.h" +#include "vie_ref_count.h" +#include "vie_shared_data.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// ViENetworkImpl +// ---------------------------------------------------------------------------- + +class ViENetworkImpl : public virtual ViESharedData, + public ViENetwork, + public ViERefCount +{ +public: + virtual int Release(); + + // Receive functions + virtual int SetLocalReceiver(const int videoChannel, + const unsigned short rtpPort, + const unsigned short rtcpPort, + const char* ipAddress); + + virtual int GetLocalReceiver(const int videoChannel, + unsigned short& rtpPort, + unsigned short& rtcpPort, char* ipAddress); + + // Send functions + virtual int SetSendDestination(const int videoChannel, + const char* ipAddress, + const unsigned short rtpPort, + const unsigned short rtcpPort, + const unsigned short sourceRtpPort, + const unsigned short sourceRtcpPort); + + virtual int GetSendDestination(const int videoChannel, char* ipAddress, + unsigned short& rtpPort, + unsigned short& rtcpPort, + unsigned short& sourceRtpPort, + unsigned short& sourceRtcpPort); + + // External transport + virtual int RegisterSendTransport(const int videoChannel, + Transport& transport); + + virtual int DeregisterSendTransport(const int videoChannel); + + virtual int ReceivedRTPPacket(const int videoChannel, const void* data, + const int length); + + virtual int ReceivedRTCPPacket(const int videoChannel, const void* data, + const int length); + + // Get info + virtual int GetSourceInfo(const int videoChannel, unsigned short& rtpPort, + unsigned short& rtcpPort, char* ipAddress, + unsigned int ipAddressLength); + + virtual int GetLocalIP(char ipAddress[64], bool ipv6); + + // IPv6 + virtual int EnableIPv6(int videoChannel); + + virtual bool IsIPv6Enabled(int videoChannel); + + // Source IP address and port filter + virtual int SetSourceFilter(const int videoChannel, + const unsigned short rtpPort, + const unsigned short rtcpPort, + const char* ipAddress); + + virtual int GetSourceFilter(const int videoChannel, + unsigned short& rtpPort, + unsigned short& rtcpPort, char* ipAddress); + + // ToS + virtual int SetSendToS(const int videoChannel, const int DSCP, + const bool useSetSockOpt); + + virtual int GetSendToS(const int videoChannel, int& DSCP, + bool& useSetSockOpt); + + // GQoS + virtual int SetSendGQoS(const int videoChannel, const bool enable, + const int serviceType, const int overrideDSCP); + + virtual int GetSendGQoS(const int videoChannel, bool& enabled, + int& serviceType, int& overrideDSCP); + + // Network settings + virtual int SetMTU(int videoChannel, unsigned int mtu); + + // Packet timout notification + virtual int SetPacketTimeoutNotification(const int videoChannel, + bool enable, int timeoutSeconds); + + // Periodic dead-or-alive reports + virtual int RegisterObserver(const int videoChannel, + ViENetworkObserver& observer); + + virtual int DeregisterObserver(const int videoChannel); + + virtual int + SetPeriodicDeadOrAliveStatus(const int videoChannel, const bool enable, + const unsigned int sampleTimeSeconds); + + // Send extra packet using the User Datagram Protocol (UDP) + virtual int SendUDPPacket(const int videoChannel, const void* data, + const unsigned int length, int& transmittedBytes, + bool useRtcpSocket); + +protected: + ViENetworkImpl(); + virtual ~ViENetworkImpl(); +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_NETWORK_IMPL_H_ diff --git a/video_engine/main/source/vie_performance_monitor.cc b/video_engine/main/source/vie_performance_monitor.cc new file mode 100644 index 0000000000..eb1483e03f --- /dev/null +++ b/video_engine/main/source/vie_performance_monitor.cc @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_performance_monitor.cc + */ + +#include "vie_performance_monitor.h" + +#include "cpu_wrapper.h" +#include "critical_section_wrapper.h" +#include "event_wrapper.h" +#include "thread_wrapper.h" +#include "tick_util.h" +#include "trace.h" +#include "vie_base.h" +#include "vie_defines.h" + +namespace webrtc { + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViEPerformanceMonitor::ViEPerformanceMonitor(int engineId) + : _engineId(engineId), + _pointerCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _ptrViEMonitorThread(NULL), + _monitorkEvent(*EventWrapper::Create()), + _averageApplicationCPU(kViECpuStartValue), + _averageSystemCPU(kViECpuStartValue), _cpu(NULL), _vieBaseObserver(NULL) +{ + _cpu = CpuWrapper::CreateCpu(); + if (_cpu) + { + _cpu->CpuUsage(); // to initialize + } else + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could not create CpuWrapper", __FUNCTION__); + } +} + +ViEPerformanceMonitor::~ViEPerformanceMonitor() +{ + Terminate(); + delete &_pointerCritsect; + delete &_monitorkEvent; + if (_cpu) + { + delete _cpu; + _cpu = NULL; + } +} + +int ViEPerformanceMonitor::Init() +{ + if (_cpu == NULL) + { + // Performance monitoring not supported + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Not supported", __FUNCTION__); + return 0; + } + + CriticalSectionScoped cs(_pointerCritsect); + if (_ptrViEMonitorThread == NULL) + { + _monitorkEvent.StartTimer(true, kViEMonitorPeriodMs); + _ptrViEMonitorThread + = ThreadWrapper::CreateThread(ViEMonitorThreadFunction, this, + kNormalPriority, + "ViEPerformanceMonitor"); + unsigned tId = 0; + if (_ptrViEMonitorThread->Start(tId)) + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Performance monitor thread started %u", + __FUNCTION__, tId); + } else + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Could not start performance monitor", __FUNCTION__); + _monitorkEvent.StopTimer(); + return -1; + } + } + return 0; +} + +int ViEPerformanceMonitor::Terminate() +{ + { + _pointerCritsect.Enter(); + _vieBaseObserver = NULL; + _pointerCritsect.Leave(); + + _monitorkEvent.StopTimer(); + if (_ptrViEMonitorThread) + { + ThreadWrapper* tmpThread = _ptrViEMonitorThread; + _ptrViEMonitorThread = NULL; + _monitorkEvent.Set(); + if (tmpThread->Stop()) + { + delete tmpThread; + tmpThread = NULL; + } + } + } + return 0; +} + +int ViEPerformanceMonitor::RegisterViEBaseObserver( + ViEBaseObserver* vieBaseObserver) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s", + __FUNCTION__); + CriticalSectionScoped cs(_pointerCritsect); + if (vieBaseObserver) + { + if (_vieBaseObserver) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "%s: Observer already started", __FUNCTION__); + return -1; + } + _vieBaseObserver = vieBaseObserver; + } else + { + _vieBaseObserver = NULL; + } + return 0; +} +bool ViEPerformanceMonitor::ViEBaseObserverRegistered() +{ + CriticalSectionScoped cs(_pointerCritsect); + return _vieBaseObserver != NULL; +} + +int ViEPerformanceMonitor::GetAverageApplicationCPU(int& applicationCPU) +{ + // Not supported + return -1; +} + +int ViEPerformanceMonitor::GetAverageSystemCPU(int& systemCPU) +{ + if (_cpu) + { + return _cpu->CpuUsage(); + } + return -1; +} + +bool ViEPerformanceMonitor::ViEMonitorThreadFunction(void* obj) +{ + return static_cast (obj)->ViEMonitorProcess(); +} + +bool ViEPerformanceMonitor::ViEMonitorProcess() +{ + // Periodically triggered with time KViEMonitorPeriodMs + _monitorkEvent.Wait(kViEMonitorPeriodMs); + { + if (_ptrViEMonitorThread == NULL) + { + // Thread removed, exit + return false; + } + if (_cpu) + { + int cpuLoad = _cpu->CpuUsage(); + if (cpuLoad > 75) + { + _pointerCritsect.Enter(); + if (_vieBaseObserver) + { + _vieBaseObserver->PerformanceAlarm(cpuLoad); + } + _pointerCritsect.Leave(); + } + } + } + return true; +} +} //namespace webrtc diff --git a/video_engine/main/source/vie_performance_monitor.h b/video_engine/main/source/vie_performance_monitor.h new file mode 100644 index 0000000000..6db1367ecd --- /dev/null +++ b/video_engine/main/source/vie_performance_monitor.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_performance_monitor.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_PERFORMANCE_MONITOR_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_PERFORMANCE_MONITOR_H_ + +// Defines +#include "vie_defines.h" +#include "typedefs.h" + +namespace webrtc +{ +class CriticalSectionWrapper; +class CpuWrapper; +class EventWrapper; +class ThreadWrapper; +class ViEBaseObserver; + +class ViEPerformanceMonitor +{ +public: + ViEPerformanceMonitor(int engineId); + ~ViEPerformanceMonitor(); + + int Init(); + int Terminate(); + int RegisterViEBaseObserver(ViEBaseObserver* vieBaseObserver); + bool ViEBaseObserverRegistered(); + + // ViEBase + int GetAverageApplicationCPU(int& applicationCPU); + int GetAverageSystemCPU(int& systemCPU); + +protected: + static bool ViEMonitorThreadFunction(void* obj); + bool ViEMonitorProcess(); + +private: + enum { kViEMonitorPeriodMs = 975 }; + enum { kViECpuStartValue = 75 }; + + const int _engineId; + CriticalSectionWrapper& _pointerCritsect; + ThreadWrapper* _ptrViEMonitorThread; + EventWrapper& _monitorkEvent; + int _averageApplicationCPU; + int _averageSystemCPU; + CpuWrapper* _cpu; + ViEBaseObserver* _vieBaseObserver; +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_PERFORMANCE_MONITOR_H_ diff --git a/video_engine/main/source/vie_receiver.cc b/video_engine/main/source/vie_receiver.cc new file mode 100644 index 0000000000..2ec47fac2b --- /dev/null +++ b/video_engine/main/source/vie_receiver.cc @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * ViEChannel.cpp + */ + +#include "vie_receiver.h" + +#include "critical_section_wrapper.h" +#include "rtp_rtcp.h" +#ifdef WEBRTC_SRTP +#include "SrtpModule.h" +#endif +#include "video_coding.h" +#include "rtp_dump.h" +#include "trace.h" + +namespace webrtc { + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViEReceiver::ViEReceiver(int engineId, int channelId, + RtpRtcp& moduleRtpRtcp, + VideoCodingModule& moduleVcm) + : _receiveCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _engineId(engineId), _channelId(channelId), _rtpRtcp(moduleRtpRtcp), + _vcm(moduleVcm), +#ifdef WEBRTC_SRTP + _ptrSrtp(NULL), + _ptrSrtcp(NULL), + _ptrSrtpBuffer(NULL), + _ptrSrtcpBuffer(NULL), +#endif + _ptrExternalDecryption(NULL), _ptrDecryptionBuffer(NULL), + _rtpDump(NULL), _receiving(false) +{ + _rtpRtcp.RegisterIncomingVideoCallback(this); +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViEReceiver::~ViEReceiver() +{ + delete &_receiveCritsect; +#ifdef WEBRTC_SRTP + if (_ptrSrtpBuffer) + { + delete [] _ptrSrtpBuffer; + _ptrSrtpBuffer = NULL; + } + if (_ptrSrtcpBuffer) + { + delete [] _ptrSrtcpBuffer; + _ptrSrtcpBuffer = NULL; + } +#endif + if (_ptrDecryptionBuffer) + { + delete[] _ptrDecryptionBuffer; + _ptrDecryptionBuffer = NULL; + } + if (_rtpDump) + { + _rtpDump->Stop(); + RtpDump::DestroyRtpDump(_rtpDump); + _rtpDump = NULL; + } +} + +// ============================================================================ +// Decryption +// ============================================================================ + +// ---------------------------------------------------------------------------- +// RegisterExternalDecryption +// ---------------------------------------------------------------------------- + +int ViEReceiver::RegisterExternalDecryption(Encryption* decryption) +{ + CriticalSectionScoped cs(_receiveCritsect); + if (_ptrExternalDecryption) + { + return -1; + } + _ptrDecryptionBuffer = new WebRtc_UWord8[kViEMaxMtu]; + if (_ptrDecryptionBuffer == NULL) + { + return -1; + } + _ptrExternalDecryption = decryption; + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterExternalDecryption +// ---------------------------------------------------------------------------- + +int ViEReceiver::DeregisterExternalDecryption() +{ + CriticalSectionScoped cs(_receiveCritsect); + if (_ptrExternalDecryption == NULL) + { + return -1; + } + _ptrExternalDecryption = NULL; + return 0; +} + +#ifdef WEBRTC_SRTP +// ---------------------------------------------------------------------------- +// RegisterSRTPModule +// ---------------------------------------------------------------------------- + +int ViEReceiver::RegisterSRTPModule(SrtpModule* srtpModule) +{ + CriticalSectionScoped cs(_receiveCritsect); + if (_ptrSrtp || + srtpModule == NULL) + { + return -1; + } + _ptrSrtpBuffer = new WebRtc_UWord8[kViEMaxMtu]; + if (_ptrSrtpBuffer == NULL) + { + return -1; + } + _ptrSrtp = srtpModule; + + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterSRTPModule +// ---------------------------------------------------------------------------- + +int ViEReceiver::DeregisterSRTPModule() +{ + CriticalSectionScoped cs(_receiveCritsect); + if (_ptrSrtp == NULL) + { + return -1; + } + if (_ptrSrtpBuffer) + { + delete [] _ptrSrtpBuffer; + _ptrSrtpBuffer = NULL; + } + _ptrSrtp = NULL; + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterSRTCPModule +// ---------------------------------------------------------------------------- + +int ViEReceiver::RegisterSRTCPModule(SrtpModule* srtcpModule) +{ + CriticalSectionScoped cs(_receiveCritsect); + if (_ptrSrtcp || + srtcpModule == NULL) + { + return -1; + } + _ptrSrtcpBuffer = new WebRtc_UWord8[kViEMaxMtu]; + if (_ptrSrtcpBuffer == NULL) + { + return -1; + } + _ptrSrtcp = srtcpModule; + + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterSRTPCModule +// ---------------------------------------------------------------------------- + +int ViEReceiver::DeregisterSRTCPModule() +{ + CriticalSectionScoped cs(_receiveCritsect); + if (_ptrSrtcp == NULL) + { + return -1; + } + if (_ptrSrtcpBuffer) + { + delete [] _ptrSrtcpBuffer; + _ptrSrtcpBuffer = NULL; + } + _ptrSrtcp = NULL; + return 0; +} + +#endif + +// ---------------------------------------------------------------------------- +// IncomingRTPPacket +// +// Receives RTP packets from SocketTransport +// ---------------------------------------------------------------------------- + +void ViEReceiver::IncomingRTPPacket(const WebRtc_Word8* incomingRtpPacket, + const WebRtc_Word32 incomingRtpPacketLength, + const WebRtc_Word8* fromIP, + const WebRtc_UWord16 fromPort) +{ + InsertRTPPacket(incomingRtpPacket, incomingRtpPacketLength); + return; +} + +// ---------------------------------------------------------------------------- +// IncomingRTCPPacket +// +// Receives RTCP packets from SocketTransport +// ---------------------------------------------------------------------------- + +void ViEReceiver::IncomingRTCPPacket(const WebRtc_Word8* incomingRtcpPacket, + const WebRtc_Word32 incomingRtcpPacketLength, + const WebRtc_Word8* fromIP, + const WebRtc_UWord16 fromPort) +{ + InsertRTCPPacket(incomingRtcpPacket, incomingRtcpPacketLength); + return; +} + +// ---------------------------------------------------------------------------- +// ReceivedRTPPacket +// +// Receives RTP packets from external transport +// ---------------------------------------------------------------------------- + +int ViEReceiver::ReceivedRTPPacket(const void* rtpPacket, int rtpPacketLength) +{ + if (!_receiving) + { + return -1; + } + return InsertRTPPacket((const WebRtc_Word8*) rtpPacket, rtpPacketLength); +} + +// ---------------------------------------------------------------------------- +// ReceivedRTCPPacket +// +// Receives RTCP packets from external transport +// ---------------------------------------------------------------------------- + +int ViEReceiver::ReceivedRTCPPacket(const void* rtcpPacket, + int rtcpPacketLength) +{ + if (!_receiving) + { + return -1; + } + return InsertRTCPPacket((const WebRtc_Word8*) rtcpPacket, rtcpPacketLength); +} + +// ---------------------------------------------------------------------------- +// OnReceivedPayloadData +// +// From RtpData, callback for data from RTP module +// ---------------------------------------------------------------------------- +WebRtc_Word32 ViEReceiver::OnReceivedPayloadData(const WebRtc_UWord8* payloadData, + const WebRtc_UWord16 payloadSize, + const WebRtcRTPHeader* rtpHeader) +{ + if (rtpHeader == NULL) + { + return 0; + } + if (rtpHeader->frameType == webrtc::kFrameEmpty) + { + // Don't care about empty rtp packets, we might + // get this e.g. when using FEC + return 0; + } + if (_vcm.IncomingPacket(payloadData, payloadSize, *rtpHeader) != 0) + { + // Check this... + return -1; + } + return 0; +} + +// ============================================================================ +// Private methods +// ============================================================================ + +// ---------------------------------------------------------------------------- +// InsertRTPPacket +// ---------------------------------------------------------------------------- + +int ViEReceiver::InsertRTPPacket(const WebRtc_Word8* rtpPacket, + int rtpPacketLength) +{ + WebRtc_UWord8* receivedPacket = (WebRtc_UWord8*) (rtpPacket); + int receivedPacketLength = rtpPacketLength; + + { + CriticalSectionScoped cs(_receiveCritsect); + + if (_ptrExternalDecryption) + { + int decryptedLength = 0; + _ptrExternalDecryption->decrypt(_channelId, receivedPacket, + _ptrDecryptionBuffer, + (int) receivedPacketLength, + (int*) &decryptedLength); + if (decryptedLength <= 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "RTP decryption failed"); + return -1; + } else if (decryptedLength > kViEMaxMtu) + { + WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + " %d bytes is allocated as RTP decrytption output => memory is now corrupted", + kViEMaxMtu); + return -1; + } + receivedPacket = _ptrDecryptionBuffer; + receivedPacketLength = decryptedLength; + } +#ifdef WEBRTC_SRTP + if (_ptrSrtp) + { + int decryptedLength = 0; + _ptrSrtp->decrypt(_channelId, receivedPacket, _ptrSrtpBuffer, receivedPacketLength, &decryptedLength); + if (decryptedLength <= 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "RTP decryption failed"); + return -1; + } + else if (decryptedLength > kViEMaxMtu) + { + WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo,ViEId(_engineId, _channelId), " %d bytes is allocated as RTP decrytption output => memory is now corrupted", kViEMaxMtu); + return -1; + } + receivedPacket = _ptrSrtpBuffer; + receivedPacketLength = decryptedLength; + } +#endif + if (_rtpDump) + { + _rtpDump->DumpPacket(receivedPacket, + (WebRtc_UWord16) receivedPacketLength); + } + } + return _rtpRtcp.IncomingPacket(receivedPacket, receivedPacketLength); +} + +// ---------------------------------------------------------------------------- +// InsertRTCPPacket +// ---------------------------------------------------------------------------- + +int ViEReceiver::InsertRTCPPacket(const WebRtc_Word8* rtcpPacket, + int rtcpPacketLength) +{ + WebRtc_UWord8* receivedPacket = (WebRtc_UWord8*) rtcpPacket; + int receivedPacketLength = rtcpPacketLength; + { + CriticalSectionScoped cs(_receiveCritsect); + + if (_ptrExternalDecryption) + { + int decryptedLength = 0; + _ptrExternalDecryption->decrypt_rtcp(_channelId, receivedPacket, + _ptrDecryptionBuffer, + (int) receivedPacketLength, + (int*) &decryptedLength); + if (decryptedLength <= 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "RTP decryption failed"); + return -1; + } else if (decryptedLength > kViEMaxMtu) + { + WEBRTC_TRACE( + webrtc::kTraceCritical, + webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + " %d bytes is allocated as RTP decrytption output => memory is now corrupted", + kViEMaxMtu); + return -1; + } + receivedPacket = _ptrDecryptionBuffer; + receivedPacketLength = decryptedLength; + } +#ifdef WEBRTC_SRTP + if (_ptrSrtcp) + { + int decryptedLength = 0; + _ptrSrtcp->decrypt_rtcp(_channelId, receivedPacket, _ptrSrtcpBuffer, (int) receivedPacketLength, (int*) &decryptedLength); + if (decryptedLength <= 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "RTP decryption failed"); + return -1; + } + else if (decryptedLength > kViEMaxMtu) + { + WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, ViEId(_engineId, _channelId), " %d bytes is allocated as RTP decrytption output => memory is now corrupted", kViEMaxMtu); + return -1; + } + receivedPacket = _ptrSrtcpBuffer; + receivedPacketLength = decryptedLength; + } +#endif + if (_rtpDump) + { + _rtpDump->DumpPacket(receivedPacket, + (WebRtc_UWord16) receivedPacketLength); + } + } + return _rtpRtcp.IncomingPacket(receivedPacket, receivedPacketLength); +} + +// ---------------------------------------------------------------------------- +// StartReceive +// +// Only used for external transport +// ---------------------------------------------------------------------------- + +void ViEReceiver::StartReceive() +{ + _receiving = true; +} + +// ---------------------------------------------------------------------------- +// StopReceive +// +// Only used for external transport +// ---------------------------------------------------------------------------- + +void ViEReceiver::StopReceive() +{ + _receiving = false; +} + +// ---------------------------------------------------------------------------- +// StartRTPDump +// ---------------------------------------------------------------------------- + +int ViEReceiver::StartRTPDump(const char fileNameUTF8[1024]) +{ + CriticalSectionScoped cs(_receiveCritsect); + if (_rtpDump) + { + // Restart it if it already exists and is started + _rtpDump->Stop(); + } else + { + _rtpDump = RtpDump::CreateRtpDump(); + if (_rtpDump == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: Failed to create RTP dump", __FUNCTION__); + return -1; + } + } + if (_rtpDump->Start(fileNameUTF8) != 0) + { + RtpDump::DestroyRtpDump(_rtpDump); + _rtpDump = NULL; + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Failed to start RTP dump", __FUNCTION__); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// StopRTPDump +// ---------------------------------------------------------------------------- + +int ViEReceiver::StopRTPDump() +{ + CriticalSectionScoped cs(_receiveCritsect); + if (_rtpDump) + { + if (_rtpDump->IsActive()) + { + _rtpDump->Stop(); + } else + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: Dump not active", __FUNCTION__); + } + RtpDump::DestroyRtpDump(_rtpDump); + _rtpDump = NULL; + } else + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: RTP dump not started", + __FUNCTION__); + return -1; + } + return 0; +} + +// Implements RtpVideoFeedback +void ViEReceiver::OnReceivedIntraFrameRequest(const WebRtc_Word32 id, + const WebRtc_UWord8 message) +{ + // Don't do anything, action trigged on default module + return; +} + +void ViEReceiver::OnNetworkChanged(const WebRtc_Word32 id, + const WebRtc_UWord32 minBitrateBps, + const WebRtc_UWord32 maxBitrateBps, + const WebRtc_UWord8 fractionLost, + const WebRtc_UWord16 roundTripTimeMs, + const WebRtc_UWord16 bwEstimateKbitMin, + const WebRtc_UWord16 bwEstimateKbitMax) +{ + // Called for default module + return; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_receiver.h b/video_engine/main/source/vie_receiver.h new file mode 100644 index 0000000000..086b74e108 --- /dev/null +++ b/video_engine/main/source/vie_receiver.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_receiver.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RECEIVER_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RECEIVER_H_ + +// Defines +#include "engine_configurations.h" +#include "vie_defines.h" +#include "typedefs.h" +#include "udp_transport.h" +#include "rtp_rtcp_defines.h" + +#ifdef WEBRTC_SRTP +class SrtpModule; +#endif + +namespace webrtc +{ +class CriticalSectionWrapper; +// Forward declarations +class RtpDump; +class RtpRtcp; +class VideoCodingModule; +class Encryption; + +class ViEReceiver: public UdpTransportData, + public RtpData, + public RtpVideoFeedback +{ +public: + ViEReceiver(int engineId, int channelId, RtpRtcp& moduleRtpRtcp, + webrtc::VideoCodingModule& moduleVcm); + ~ViEReceiver(); + + int RegisterExternalDecryption(Encryption* decryption); + int DeregisterExternalDecryption(); + +#ifdef WEBRTC_SRTP + int RegisterSRTPModule(SrtpModule* srtpModule); + int DeregisterSRTPModule(); + + int RegisterSRTCPModule(SrtpModule* srtpModule); + int DeregisterSRTCPModule(); +#endif + + void StartReceive(); + void StopReceive(); + int StartRTPDump(const char fileNameUTF8[1024]); + int StopRTPDump(); + + // From SocketTransportData, receiving packets from the socket + virtual void IncomingRTPPacket(const WebRtc_Word8* incomingRtpPacket, + const WebRtc_Word32 incomingRtpPacketLength, + const WebRtc_Word8* fromIP, + const WebRtc_UWord16 fromPort); + virtual void IncomingRTCPPacket(const WebRtc_Word8* incomingRtcpPacket, + const WebRtc_Word32 incomingRtcpPacketLength, + const WebRtc_Word8* fromIP, + const WebRtc_UWord16 fromPort); + + // Receives packets from external transport + int ReceivedRTPPacket(const void* rtpPacket, int rtpPacketLength); + + int ReceivedRTCPPacket(const void* rtcpPacket, int rtcpPacketLength); + + // From RtpData, callback for data from RTP module + virtual WebRtc_Word32 + OnReceivedPayloadData(const WebRtc_UWord8* payloadData, + const WebRtc_UWord16 payloadSize, + const WebRtcRTPHeader* rtpHeader); + + // Implements RtpVideoFeedback + virtual void OnReceivedIntraFrameRequest(const WebRtc_Word32 id, + const WebRtc_UWord8 message = 0); + virtual void OnNetworkChanged(const WebRtc_Word32 id, + const WebRtc_UWord32 minBitrateBps, + const WebRtc_UWord32 maxBitrateBps, + const WebRtc_UWord8 fractionLost, + const WebRtc_UWord16 roundTripTimeMs, + const WebRtc_UWord16 bwEstimateKbitMin, + const WebRtc_UWord16 bwEstimateKbitMax); +private: + int InsertRTPPacket(const WebRtc_Word8* rtpPacket, int rtpPacketLength); + int InsertRTCPPacket(const WebRtc_Word8* rtcpPacket, int rtcpPacketLength); + // Registered members + CriticalSectionWrapper& _receiveCritsect; + int _engineId; + int _channelId; + RtpRtcp& _rtpRtcp; + VideoCodingModule& _vcm; + +#ifdef WEBRTC_SRTP + SrtpModule* _ptrSrtp; + SrtpModule* _ptrSrtcp; + WebRtc_UWord8* _ptrSrtpBuffer; + WebRtc_UWord8* _ptrSrtcpBuffer; +#endif + Encryption* _ptrExternalDecryption; + WebRtc_UWord8* _ptrDecryptionBuffer; + RtpDump* _rtpDump; + bool _receiving; // Only needed to protect external transport +}; +} // namespace webrt +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RECEIVER_H_ diff --git a/video_engine/main/source/vie_ref_count.cc b/video_engine/main/source/vie_ref_count.cc new file mode 100644 index 0000000000..b935567668 --- /dev/null +++ b/video_engine/main/source/vie_ref_count.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * ViERefCount.cpp + */ + + +#include "vie_ref_count.h" +#include "critical_section_wrapper.h" + + +ViERefCount::ViERefCount() : + _count(0), + _crit(*webrtc::CriticalSectionWrapper::CreateCriticalSection()) +{ +} + +ViERefCount::~ViERefCount() +{ + delete &_crit; +} + +ViERefCount& +ViERefCount::operator++(int) +{ + webrtc::CriticalSectionScoped lock(_crit); + _count++; + return *this; +} + +ViERefCount& +ViERefCount::operator--(int) +{ + webrtc::CriticalSectionScoped lock(_crit); + _count--; + return *this; +} + +void +ViERefCount::Reset() +{ + webrtc::CriticalSectionScoped lock(_crit); + _count = 0; +} + +int +ViERefCount::GetCount() const +{ + return _count; +} diff --git a/video_engine/main/source/vie_ref_count.h b/video_engine/main/source/vie_ref_count.h new file mode 100644 index 0000000000..ccf6279667 --- /dev/null +++ b/video_engine/main/source/vie_ref_count.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_ref_count.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_REF_COUNT_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_REF_COUNT_H_ + +namespace webrtc { +class CriticalSectionWrapper; +} + +class ViERefCount +{ +public: + ViERefCount(); + ~ViERefCount(); + + ViERefCount& operator++(int); + ViERefCount& operator--(int); + + void Reset(); + int GetCount() const; + +private: + volatile int _count; + webrtc::CriticalSectionWrapper& _crit; +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_REF_COUNT_H_ diff --git a/video_engine/main/source/vie_render_impl.cc b/video_engine/main/source/vie_render_impl.cc new file mode 100644 index 0000000000..add6909c13 --- /dev/null +++ b/video_engine/main/source/vie_render_impl.cc @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_render_impl.cc + */ + +#include "vie_render_impl.h" + +// Defines +#include "engine_configurations.h" +#include "vie_defines.h" + +#include "trace.h" +#include "video_render.h" +#include "video_render_defines.h" +#include "vie_errors.h" +#include "vie_impl.h" +#include "vie_capturer.h" +#include "vie_channel.h" +#include "vie_frame_provider_base.h" +#include "vie_channel_manager.h" +#include "vie_input_manager.h" +#include "vie_render_manager.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// GetInterface +// ---------------------------------------------------------------------------- + +ViERender* ViERender::GetInterface(VideoEngine* videoEngine) +{ +#ifdef WEBRTC_VIDEO_ENGINE_RENDER_API + if (videoEngine == NULL) + { + return NULL; + } + VideoEngineImpl* vieImpl = reinterpret_cast (videoEngine); + ViERenderImpl* vieRenderImpl = vieImpl; + (*vieRenderImpl)++; // Increase ref count + + return vieRenderImpl; +#else + return NULL; +#endif +} + +// ---------------------------------------------------------------------------- +// Release +// +// Releases the interface, i.e. reduces the reference counter. The number of +// remaining references is returned, -1 if released too many times. +// ---------------------------------------------------------------------------- + +int ViERenderImpl::Release() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "ViERender::Release()"); + (*this)--; // Decrease ref count + + WebRtc_Word32 refCount = GetCount(); + if (refCount < 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, + "ViERender release too many times"); + // SetLastError() + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId, + "ViERender reference count: %d", refCount); + return refCount; +} + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViERenderImpl::ViERenderImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViERenderImpl::ViERenderImpl() Ctor"); +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViERenderImpl::~ViERenderImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViERenderImpl::~ViERenderImpl() Dtor"); +} + +// ============================================================================ +// Registration of render module +// ============================================================================ + +// ---------------------------------------------------------------------------- +// RegisterVideoRenderModule +// +// Registers a video render module, must be called before +// AddRenderer is called for an input stream associated +// with the same window as the module. +// ---------------------------------------------------------------------------- + +int ViERenderImpl::RegisterVideoRenderModule( + VideoRender& renderModule) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s (&renderModule: %p)", __FUNCTION__, &renderModule); + + if (_renderManager.RegisterVideoRenderModule(renderModule) != 0) + { + // Error logging is done in RegisterVideoRenderModule + SetLastError(kViERenderUnknownError); + return -1; + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// DeRegisterVideoRenderModule +// +// De-registers a video render module, must be called after +// RemoveRenderer has been called for all input streams associated +// with the same window as the module. +// ---------------------------------------------------------------------------- + +int ViERenderImpl::DeRegisterVideoRenderModule( + VideoRender& renderModule) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s (&renderModule: %p)", __FUNCTION__, &renderModule); + if (_renderManager.DeRegisterVideoRenderModule(renderModule) != 0) + { + // Error logging is done in DeRegisterVideoRenderModule + SetLastError(kViERenderUnknownError); + return -1; + } + + return 0; +} + +// ============================================================================ +// Add renderer +// ============================================================================ + +int ViERenderImpl::AddRenderer(const int renderId, void* window, + const unsigned int zOrder, const float left, + const float top, const float right, + const float bottom) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s (renderId: %d, window: 0x%p, zOrder: %u, left: %f, " + "top: %f, right: %f, bottom: %f)", + __FUNCTION__, renderId, window, zOrder, left, top, right, + bottom); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + { // Check if the renderer exist already + ViERenderManagerScoped rs(_renderManager); + if (rs.Renderer(renderId) != NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - Renderer already exist %d.", __FUNCTION__, + renderId); + SetLastError(kViERenderAlreadyExists); + return -1; + } + } + + if (renderId >= kViEChannelIdBase && renderId <= kViEChannelIdMax) + { + // This is a channel + ViEChannelManagerScoped cm(_channelManager); + ViEFrameProviderBase* frameProvider = cm.Channel(renderId); + if (frameProvider == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: FrameProvider id %d doesn't exist", __FUNCTION__, + renderId); + SetLastError(kViERenderInvalidRenderId); + return -1; + } + ViERenderer* renderer = _renderManager.AddRenderStream(renderId, + window, zOrder, + left, top, + right, bottom); + if (renderer == NULL) + { + SetLastError(kViERenderUnknownError); + return -1; + } + return frameProvider->RegisterFrameCallback(renderId, renderer); + } + else // camera or file + { + ViEInputManagerScoped is(_inputManager); + ViEFrameProviderBase* frameProvider = is.FrameProvider(renderId); + if (frameProvider == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: FrameProvider id %d doesn't exist", __FUNCTION__, + renderId); + SetLastError(kViERenderInvalidRenderId); + return -1; + } + ViERenderer* renderer = _renderManager.AddRenderStream(renderId, + window, zOrder, + left, top, + right, bottom); + if (renderer == NULL) + { + SetLastError(kViERenderUnknownError); + return -1; + } + return frameProvider->RegisterFrameCallback(renderId, renderer); + } + SetLastError(kViERenderInvalidRenderId); + return -1; + +} + +int ViERenderImpl::RemoveRenderer(const int renderId) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), + "%s(renderId: %d)", __FUNCTION__, renderId); + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + ViERenderer* renderer = NULL; + { + ViERenderManagerScoped rs(_renderManager); + renderer = rs.Renderer(renderId); + if (!renderer) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_instanceId), + "%s No render exist with renderId: %d", __FUNCTION__, + renderId); + SetLastError(kViERenderInvalidRenderId); + return -1; + } + } // Leave the scope lock since we don't want to lock two managers + // simultanousely + + if (renderId >= kViEChannelIdBase && renderId <= kViEChannelIdMax) + { + // This is a channel + ViEChannelManagerScoped cm(_channelManager); + ViEChannel* channel = cm.Channel(renderId); + if (!channel) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: no channel with id %d exists ", __FUNCTION__, + renderId); + SetLastError(kViERenderInvalidRenderId); + return -1; + } + channel->DeregisterFrameCallback(renderer); + } + else //Provider owned by inputmanager - ie file or capture device + { + ViEInputManagerScoped is(_inputManager); + ViEFrameProviderBase* provider = is.FrameProvider(renderId); + if (!provider) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: no provider with id %d exists ", __FUNCTION__, + renderId); + SetLastError(kViERenderInvalidRenderId); + return -1; + } + provider->DeregisterFrameCallback(renderer); + + } + if (_renderManager.RemoveRenderStream(renderId) != 0) + { + SetLastError(kViERenderUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// Start/stop +// ============================================================================ + +// ---------------------------------------------------------------------------- +// StartRender +// +// Starts rendering the stream from the channel +// ---------------------------------------------------------------------------- + +int ViERenderImpl::StartRender(const int renderId) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, renderId), "%s(channel: %d)", __FUNCTION__, + renderId); + + ViERenderManagerScoped rs(_renderManager); + ViERenderer* ptrRender = rs.Renderer(renderId); + if (ptrRender == NULL) + { + // No renderer for this channel + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, renderId), + "%s: No renderer with render Id %d exist.", __FUNCTION__, + renderId); + SetLastError(kViERenderInvalidRenderId); + return -1; + } + + if (ptrRender->StartRender() != 0) + { + SetLastError(kViERenderUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// StopRender +// +// Stop rendering a stream +// ---------------------------------------------------------------------------- + +int ViERenderImpl::StopRender(const int renderId) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, renderId), "%s(channel: %d)", __FUNCTION__, + renderId); + + ViERenderManagerScoped rs(_renderManager); + ViERenderer* ptrRender = rs.Renderer(renderId); + if (ptrRender == NULL) + { + // No renderer for this channel + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, renderId), + "%s: No renderer with renderId %d exist.", __FUNCTION__, + renderId); + SetLastError(kViERenderInvalidRenderId); + return -1; + } + if (ptrRender->StopRender() != 0) + { + SetLastError(kViERenderUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// Stream configurations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ConfigureRender +// +// Reconfigures an already added render stream +// ---------------------------------------------------------------------------- + +int ViERenderImpl::ConfigureRender(int renderId, const unsigned int zOrder, + const float left, const float top, + const float right, const float bottom) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId, renderId), + "%s(channel: %d)", __FUNCTION__, renderId); + + ViERenderManagerScoped rs(_renderManager); + ViERenderer* ptrRender = rs.Renderer(renderId); + if (ptrRender == NULL) + { + // No renderer for this channel + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, renderId), + "%s: No renderer with renderId %d exist.", __FUNCTION__, + renderId); + SetLastError(kViERenderInvalidRenderId); + return -1; + } + + if (ptrRender->ConfigureRenderer(zOrder, left, top, right, bottom) != 0) + { + SetLastError(kViERenderUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// MirrorRenderStream +// +// Enables mirror rendering +// ---------------------------------------------------------------------------- + +int ViERenderImpl::MirrorRenderStream(const int renderId, const bool enable, + const bool mirrorXAxis, + const bool mirrorYAxis) +{ + ViERenderManagerScoped rs(_renderManager); + ViERenderer* ptrRender = rs.Renderer(renderId); + if (ptrRender == NULL) + { + // No renderer for this channel + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, renderId), + "%s: No renderer with renderId %d exist.", __FUNCTION__, + renderId); + SetLastError(kViERenderInvalidRenderId); + return -1; + } + if (ptrRender->EnableMirroring(renderId, enable, mirrorXAxis, mirrorYAxis) + != 0) + { + SetLastError(kViERenderUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// External render +// ============================================================================ + + +// ---------------------------------------------------------------------------- +// +// +// AddRenderer +// ---------------------------------------------------------------------------- + +int ViERenderImpl::AddRenderer(const int renderId, + webrtc::RawVideoType videoInputFormat, + ExternalRenderer* externalRenderer) +{ + // check if the client requested a format that we can convert the frames to + if (videoInputFormat != webrtc::kVideoI420 + && videoInputFormat != webrtc::kVideoYV12 + && videoInputFormat != webrtc::kVideoYUY2 + && videoInputFormat != webrtc::kVideoUYVY + && videoInputFormat != webrtc::kVideoARGB + && videoInputFormat != webrtc::kVideoRGB24 + && videoInputFormat != webrtc::kVideoRGB565 + && videoInputFormat != webrtc::kVideoARGB4444 + && videoInputFormat != webrtc::kVideoARGB1555) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, renderId), + "%s: Unsupported video frame format requested", + __FUNCTION__, renderId); + SetLastError(kViERenderInvalidFrameFormat); + return -1; + } + + if (!IsInitialized()) + { + SetLastError(kViENotInitialized); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - ViE instance %d not initialized", __FUNCTION__, + _instanceId); + return -1; + } + + { // Check if the renderer exist already + ViERenderManagerScoped rs(_renderManager); + if (rs.Renderer(renderId) != NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s - Renderer already exist %d.", __FUNCTION__, + renderId); + SetLastError(kViERenderAlreadyExists); + return -1; + } + } + + if (renderId >= kViEChannelIdBase && renderId <= kViEChannelIdMax) + { + // This is a channel + ViEChannelManagerScoped cm(_channelManager); + ViEFrameProviderBase* frameProvider = cm.Channel(renderId); + if (frameProvider == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: FrameProvider id %d doesn't exist", __FUNCTION__, + renderId); + SetLastError(kViERenderInvalidRenderId); + return -1; + } + ViERenderer* ptrRender = _renderManager.AddRenderStream(renderId, NULL, + 0, 0.0f, 0.0f, + 1.0f, 1.0f); + if (ptrRender == NULL) + { + SetLastError(kViERenderUnknownError); + return -1; + } + if (-1 == ptrRender->SetExternalRenderer(renderId, videoInputFormat, + externalRenderer)) + { + SetLastError(kViERenderUnknownError); + return -1; + } + + return frameProvider->RegisterFrameCallback(renderId, ptrRender); + } + else // camera or file + { + ViEInputManagerScoped is(_inputManager); + ViEFrameProviderBase* frameProvider = is.FrameProvider(renderId); + if (frameProvider == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), + "%s: FrameProvider id %d doesn't exist", __FUNCTION__, + renderId); + SetLastError(kViERenderInvalidRenderId); + return -1; + } + ViERenderer* ptrRender = _renderManager.AddRenderStream(renderId, NULL, + 0, 0.0f, 0.0f, + 1.0f, 1.0f); + if (ptrRender == NULL) + { + SetLastError(kViERenderUnknownError); + return -1; + } + if (-1 == ptrRender->SetExternalRenderer(renderId, videoInputFormat, + externalRenderer)) + { + SetLastError(kViERenderUnknownError); + return -1; + } + return frameProvider->RegisterFrameCallback(renderId, ptrRender); + } + SetLastError(kViERenderInvalidRenderId); + return -1; + +} + +} // namespace webrtc diff --git a/video_engine/main/source/vie_render_impl.h b/video_engine/main/source/vie_render_impl.h new file mode 100644 index 0000000000..2d1bd3653c --- /dev/null +++ b/video_engine/main/source/vie_render_impl.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_render_impl.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RENDER_IMPL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RENDER_IMPL_H_ + +#include "vie_defines.h" + +#include "typedefs.h" +#include "video_render_defines.h" +#include "vie_ref_count.h" +#include "vie_render.h" +#include "vie_shared_data.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// ViERenderImpl +// ---------------------------------------------------------------------------- + +class ViERenderImpl: public virtual ViESharedData, + public ViERender, + public ViERefCount +{ +public: + virtual int Release(); + + // Registration of render module + virtual int RegisterVideoRenderModule(VideoRender& renderModule); + + virtual int DeRegisterVideoRenderModule( + VideoRender& renderModule); + + // Add/remove renderer + virtual int AddRenderer(const int renderId, void* window, + const unsigned int zOrder, const float left, + const float top, const float right, + const float bottom); + + virtual int RemoveRenderer(const int renderId); + + // Start/stop + virtual int StartRender(const int renderId); + + virtual int StopRender(const int renderId); + + virtual int ConfigureRender(int renderId, const unsigned int zOrder, + const float left, const float top, + const float right, const float bottom); + + virtual int MirrorRenderStream(const int renderId, const bool enable, + const bool mirrorXAxis, + const bool mirrorYAxis); + + // External render + virtual int AddRenderer(const int renderId, + webrtc::RawVideoType videoInputFormat, + ExternalRenderer* renderer); + +protected: + ViERenderImpl(); + virtual ~ViERenderImpl(); +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RENDER_IMPL_H_ diff --git a/video_engine/main/source/vie_render_manager.cc b/video_engine/main/source/vie_render_manager.cc new file mode 100644 index 0000000000..3d82c4e1e2 --- /dev/null +++ b/video_engine/main/source/vie_render_manager.cc @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * ViERenderManager.cpp + */ + +#include "vie_render_manager.h" +#include "engine_configurations.h" +#include "vie_defines.h" + +#include "critical_section_wrapper.h" +#include "video_render.h" +#include "video_render_defines.h" +#include "rw_lock_wrapper.h" +#include "trace.h" + +namespace webrtc { + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + + + +ViERenderManagerScoped::ViERenderManagerScoped(const ViERenderManager& vieRenderManager) + : + ViEManagerScopedBase(vieRenderManager) +{ + +} + + +// ---------------------------------------------------------------------------- +// Renderer() +// +// Returns a pointer to the ViERender object +// ---------------------------------------------------------------------------- + +ViERenderer* ViERenderManagerScoped::Renderer(WebRtc_Word32 renderId) const +{ + return static_cast (_vieManager)->ViERenderPtr(renderId); +} + + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViERenderManager::ViERenderManager(WebRtc_Word32 engineId) : + _listCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _engineId(engineId), + _streamToViERenderer(), + _renderList(), + _useExternalRenderModule(false) +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(engineId), + "ViERenderManager::ViERenderManager(engineId: %d) - Constructor", engineId); +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViERenderManager::~ViERenderManager() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(_engineId), + "ViERenderManager Destructor, engineId: %d", _engineId); + + while(_streamToViERenderer.Size()!=0) + { + MapItem* item=_streamToViERenderer.First(); + assert(item); + const WebRtc_Word32 renderId=item->GetId(); + item=NULL;// Deleted be RemoveRenderStream; + RemoveRenderStream(renderId); + } + delete &_listCritsect; + +} + +// ---------------------------------------------------------------------------- +// RegisterVideoRenderModule +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViERenderManager::RegisterVideoRenderModule(VideoRender& renderModule) +{ + // See if there is already a render module registered for the window that + // the registrant render module is associated with + VideoRender* ptrCurrentModule = FindRenderModule(renderModule.Window()); + if (ptrCurrentModule) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "A module is already registered for this window (window=%p, current module=%p, registrant module=%p", + renderModule.Window(), ptrCurrentModule, &renderModule); + return -1; + } + + // Register module + _renderList.PushBack(static_cast(&renderModule)); + _useExternalRenderModule=true; + + return 0; +} + +// ---------------------------------------------------------------------------- +// DeRegisterVideoRenderModule +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViERenderManager::DeRegisterVideoRenderModule(VideoRender& renderModule) +{ + // Check if there are streams in the module + WebRtc_UWord32 nStreams = renderModule.GetNumIncomingRenderStreams(); + if (nStreams != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), + "There are still %d streams in this module, cannot de-register", nStreams); + return -1; + } + + // Erase the render module from the map + ListItem* listItem = NULL; + bool found = false; + for (listItem = _renderList.First(); listItem != NULL; listItem = _renderList.Next(listItem)) + { + if (&renderModule == static_cast(listItem->GetItem())) + { + // We've found our renderer + _renderList.Erase(listItem); + found = true; + break; + } + } + if (!found) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "Module not registered"); + return -1; + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// AddRenderStream +// ---------------------------------------------------------------------------- + +ViERenderer* ViERenderManager::AddRenderStream(const WebRtc_Word32 renderId, + void* window, + const WebRtc_UWord32 zOrder, + const float left, + const float top, + const float right, + const float bottom) +{ + CriticalSectionScoped cs(_listCritsect); + + if (_streamToViERenderer.Find(renderId) != NULL) + { + // This stream is already added to a renderer, not allowed! + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "Render stream already exists"); + return NULL; + } + + // Get the render module for this window + VideoRender* ptrRenderer = FindRenderModule(window); + if (ptrRenderer == NULL) + { + // No render module for this window, create a new one + #ifndef WEBRTC_VIDEO_EXTERNAL_CAPTURE_AND_RENDER + ptrRenderer = VideoRender::CreateVideoRender(ViEModuleId(_engineId, -1), window, false); + #else + ptrRenderer = VideoRender::CreateVideoRender(ViEModuleId(_engineId, -1), window, false, kRenderExternal); + #endif //WEBRTC_VIDEO_EXTERNAL_CAPTURE_AND_RENDER + if (!ptrRenderer) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "Could not create new render module"); + return NULL; + } + _renderList.PushBack((void*) ptrRenderer); + } + + ViERenderer* vieRenderer= ViERenderer::CreateViERenderer(renderId,_engineId,*ptrRenderer,*this,zOrder,left,top,right,bottom); + if(!vieRenderer) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId,renderId), "Could not create new render stream"); + return NULL; + } + + _streamToViERenderer.Insert(renderId, vieRenderer); + + return vieRenderer; +} + +// ---------------------------------------------------------------------------- +// RemoveRenderStream +// ---------------------------------------------------------------------------- + +WebRtc_Word32 ViERenderManager::RemoveRenderStream(const WebRtc_Word32 renderId) +{ + // We need exclusive right to the items in the rendermanager to delete a stream + ViEManagerWriteScoped(*this); + + // Protect the list/map + CriticalSectionScoped cs(_listCritsect); + + MapItem* mapItem = _streamToViERenderer.Find(renderId); + if (mapItem == NULL) + { + // No such stream + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId), "No renderer for this stream found, channelId"); + return 0; + } + + // Get the vieRender object. + ViERenderer* ptrViERenderer = static_cast(mapItem->GetItem()); + assert(ptrViERenderer); + + // Get the render module pointer for this vieRender object + VideoRender& renderer=ptrViERenderer->RenderModule(); + + // Delete the vieRender. + // This deletes the stream in the render module. + delete ptrViERenderer; + + // Remove from the stream map + _streamToViERenderer.Erase(mapItem); + + // Check if there are other streams in the module + if (!_useExternalRenderModule && renderer.GetNumIncomingRenderStreams() == 0) + { + // Erase the render module from the map + ListItem* listItem = NULL; + for (listItem = _renderList.First(); listItem != NULL; listItem = _renderList.Next(listItem)) + { + if (&renderer == static_cast(listItem->GetItem())) + { + // We've found our renderer + _renderList.Erase(listItem); + break; + } + } + // Destroy the module + VideoRender::DestroyVideoRender(&renderer); + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// FindRenderModule +// +// Returns a pointer to the render module if it exists in the render list. +// Assumed protected +// ---------------------------------------------------------------------------- + +VideoRender* ViERenderManager::FindRenderModule(void* window) +{ + VideoRender* ptrRenderer = NULL; + ListItem* listItem = NULL; + for (listItem = _renderList.First(); listItem != NULL; listItem = _renderList.Next(listItem)) + { + ptrRenderer = static_cast(listItem->GetItem()); + if (ptrRenderer == NULL) + { + break; + } + if (ptrRenderer->Window() == window) + { + // We've found the render module + break; + } + ptrRenderer = NULL; + } + return ptrRenderer; +} + +ViERenderer* ViERenderManager::ViERenderPtr(WebRtc_Word32 renderId) const +{ + ViERenderer* ptrRenderer = NULL; + + MapItem* mapItem = _streamToViERenderer.Find(renderId); + if (mapItem == NULL) + { + // No such stream in any renderer + return NULL; + } + ptrRenderer = static_cast(mapItem->GetItem()); + + return ptrRenderer; +} + +} //namespace webrtc + diff --git a/video_engine/main/source/vie_render_manager.h b/video_engine/main/source/vie_render_manager.h new file mode 100644 index 0000000000..b8da6da0e8 --- /dev/null +++ b/video_engine/main/source/vie_render_manager.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_render_manager.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RENDER_MANAGER_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RENDER_MANAGER_H_ + +// Defines +#include "engine_configurations.h" +#include "vie_defines.h" + +#include "typedefs.h" +#include "list_wrapper.h" +#include "map_wrapper.h" + +#include "vie_manager_base.h" + +#include "vie_renderer.h" + +namespace webrtc { + +class CriticalSectionWrapper; +class RWLockWrapper; +class VideoRender; +class VideoRenderCallback; + +class ViERenderManager: private ViEManagerBase +{ + friend class ViERenderManagerScoped; +public: + ViERenderManager(WebRtc_Word32 engineId); + ~ViERenderManager(); + + WebRtc_Word32 RegisterVideoRenderModule(VideoRender& renderModule); + WebRtc_Word32 DeRegisterVideoRenderModule(VideoRender& renderModule); + + ViERenderer* AddRenderStream(const WebRtc_Word32 renderId, + void* window, + const WebRtc_UWord32 zOrder, + const float left, + const float top, + const float right, + const float bottom); + + WebRtc_Word32 RemoveRenderStream(WebRtc_Word32 renderId); + + VideoRender* FindRenderModule(void* window); + +private: + + // Methods used by ViERenderScoped + ViERenderer* ViERenderPtr(WebRtc_Word32 renderId) const; + + // Members + CriticalSectionWrapper& _listCritsect; + + WebRtc_Word32 _engineId; + MapWrapper _streamToViERenderer; // Protected by ViEManagerBase + ListWrapper _renderList; + bool _useExternalRenderModule; +}; + + +// ------------------------------------------------------------------ +// ViERenderManagerScoped +// ------------------------------------------------------------------ +class ViERenderManagerScoped: private ViEManagerScopedBase +{ +public: + ViERenderManagerScoped(const ViERenderManager& vieRenderManager); + ViERenderer* Renderer(WebRtc_Word32 renderId) const; +}; + +} //namespace webrtc + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RENDER_MANAGER_H_ diff --git a/video_engine/main/source/vie_renderer.cc b/video_engine/main/source/vie_renderer.cc new file mode 100644 index 0000000000..7522d1ae0d --- /dev/null +++ b/video_engine/main/source/vie_renderer.cc @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vie_renderer.h" +#include "video_render.h" +#include "video_render_defines.h" +#include "vie_render_manager.h" +#include "vplib.h" + +namespace webrtc { + +ViERenderer* ViERenderer::CreateViERenderer( + const WebRtc_Word32 renderId, + const WebRtc_Word32 engineId, + VideoRender& renderModule, + ViERenderManager& renderManager, + const WebRtc_UWord32 zOrder, + const float left, + const float top, + const float right, + const float bottom) +{ + ViERenderer* self=new ViERenderer(renderId,engineId,renderModule,renderManager); + if(!self || self->Init(zOrder,left,top,right,bottom)!=0) + { + delete self; + self=NULL; + } + return self; +} + +ViERenderer::~ViERenderer(void) +{ + if(_ptrRenderCallback) + { + _renderModule.DeleteIncomingRenderStream( _renderId); + } + + if(_ptrIncomingExternalCallback){ + delete _ptrIncomingExternalCallback; + } + +} + +ViERenderer::ViERenderer(const WebRtc_Word32 renderId,const WebRtc_Word32 engineId, + VideoRender& renderModule, + ViERenderManager& renderManager) +: +_renderId(renderId), +_engineId(engineId), +_renderModule(renderModule), +_renderManager(renderManager), +_ptrRenderCallback(NULL), +_ptrIncomingExternalCallback(new ViEExternalRendererImpl()) +{ + +} + +WebRtc_Word32 ViERenderer::Init(const WebRtc_UWord32 zOrder, + const float left, + const float top, + const float right, + const float bottom) +{ + _ptrRenderCallback = (VideoRenderCallback*)_renderModule.AddIncomingRenderStream( _renderId, zOrder, left, top, right, bottom); + if (_ptrRenderCallback == NULL) + { + // Logging done + return -1; + } + + return 0; +} + +WebRtc_Word32 ViERenderer::GetLastRenderedFrame(const WebRtc_Word32 renderID, webrtc::VideoFrame& videoFrame) +{ + return _renderModule.GetLastRenderedFrame(renderID, videoFrame); +} + +WebRtc_Word32 ViERenderer::StartRender() +{ + return _renderModule.StartRender(_renderId); +} +WebRtc_Word32 ViERenderer::StopRender() +{ + return _renderModule.StopRender(_renderId); +} + + // Implement ViEFrameCallback +void ViERenderer::DeliverFrame(int id, + webrtc::VideoFrame& videoFrame, + int numCSRCs, + const WebRtc_UWord32 CSRC[kRtpCsrcSize]) +{ + + + _ptrRenderCallback->RenderFrame(_renderId,videoFrame); + +} + +// Implement ViEFrameCallback +void ViERenderer::ProviderDestroyed(int id) +{ + _renderManager.RemoveRenderStream(_renderId); // Remove the render stream since the provider is destroyed. +} + +VideoRender& ViERenderer::RenderModule() +{ + return _renderModule; +} + +WebRtc_Word32 ViERenderer::ConfigureRenderer(const unsigned int zOrder, + const float left, + const float top, + const float right, + const float bottom) +{ + return _renderModule.ConfigureRenderer(_renderId, zOrder, left, top, right, bottom); +} + + + +WebRtc_Word32 ViERenderer::SetTimeoutImage(const webrtc::VideoFrame& timeoutImage,const WebRtc_Word32 timeoutValue) +{ + return _renderModule.SetTimeoutImage(_renderId,timeoutImage,timeoutValue); +} + +WebRtc_Word32 ViERenderer::SetRenderStartImage(const webrtc::VideoFrame& startImage) +{ + return _renderModule.SetStartImage(_renderId,startImage); +} + + + +WebRtc_Word32 ViERenderer::EnableMirroring(const WebRtc_Word32 renderId, const bool enable, const bool mirrorXAxis, const bool mirrorYAxis) +{ + return _renderModule.MirrorRenderStream(renderId, enable, mirrorXAxis, mirrorYAxis); +} + + +WebRtc_Word32 ViERenderer::SetExternalRenderer(const WebRtc_Word32 renderId, webrtc::RawVideoType videoInputFormat, ExternalRenderer* externalRenderer) +{ + if(NULL == _ptrIncomingExternalCallback){ + return -1; + } + + _ptrIncomingExternalCallback->SetViEExternalRenderer(externalRenderer, videoInputFormat); + return _renderModule.AddExternalRenderCallback(renderId, _ptrIncomingExternalCallback); +} + + + +ViEExternalRendererImpl::ViEExternalRendererImpl() : +_externalRenderer(NULL), +_externalRendererFormat(), +_externalRendererWidth(0), +_externalRendererHeight(0) +{ +} + +int ViEExternalRendererImpl::SetViEExternalRenderer(ExternalRenderer* externalRenderer, webrtc::RawVideoType videoInputFormat) +{ + _externalRenderer = externalRenderer; + _externalRendererFormat = videoInputFormat; + return 0; +} + +// implements VideoRenderCallback +WebRtc_Word32 ViEExternalRendererImpl::RenderFrame(const WebRtc_UWord32 streamId, + webrtc::VideoFrame& videoFrame) +{ + webrtc::VideoFrame convertedFrame; + webrtc::VideoFrame* pConvertedFrame = &convertedFrame; + + // convert to requested format + switch(_externalRendererFormat) + { + case webrtc::kVideoI420: + pConvertedFrame = &videoFrame; + break; + case webrtc::kVideoYV12: + convertedFrame.VerifyAndAllocate(webrtc::CalcBufferSize(webrtc::kYV12,videoFrame.Width(),videoFrame.Height())); + webrtc::ConvertI420ToYV12(videoFrame.Buffer(), convertedFrame.Buffer(), videoFrame.Width(), videoFrame.Height(), 0); + break; + case webrtc::kVideoYUY2: + convertedFrame.VerifyAndAllocate(webrtc::CalcBufferSize(webrtc::kYUY2,videoFrame.Width(),videoFrame.Height())); + webrtc::ConvertI420ToYUY2(videoFrame.Buffer(), convertedFrame.Buffer(), videoFrame.Width(), videoFrame.Height(), 0); + break; + case webrtc::kVideoUYVY: + convertedFrame.VerifyAndAllocate(webrtc::CalcBufferSize(webrtc::kUYVY,videoFrame.Width(),videoFrame.Height())); + webrtc::ConvertI420ToUYVY(videoFrame.Buffer(), convertedFrame.Buffer(), videoFrame.Width(), videoFrame.Height(), 0); + break; + case webrtc::kVideoIYUV: + // no conversion available + break; + case webrtc::kVideoARGB: + convertedFrame.VerifyAndAllocate(webrtc::CalcBufferSize(webrtc::kARGB,videoFrame.Width(),videoFrame.Height())); + webrtc::ConvertI420ToARGB(videoFrame.Buffer(), convertedFrame.Buffer(), videoFrame.Width(), videoFrame.Height(), 0); + break; + case webrtc::kVideoRGB24: + convertedFrame.VerifyAndAllocate(webrtc::CalcBufferSize(webrtc::kRGB24,videoFrame.Width(),videoFrame.Height())); + webrtc::ConvertI420ToRGB24(videoFrame.Buffer(), convertedFrame.Buffer(), videoFrame.Width(), videoFrame.Height()); + break; + case webrtc::kVideoRGB565: + convertedFrame.VerifyAndAllocate(webrtc::CalcBufferSize(webrtc::kRGB565,videoFrame.Width(),videoFrame.Height())); + webrtc::ConvertI420ToRGB565(videoFrame.Buffer(), convertedFrame.Buffer(), videoFrame.Width(), videoFrame.Height()); + break; + case webrtc::kVideoARGB4444: + convertedFrame.VerifyAndAllocate(webrtc::CalcBufferSize(webrtc::kARGB4444,videoFrame.Width(),videoFrame.Height())); + webrtc::ConvertI420ToARGB4444(videoFrame.Buffer(), convertedFrame.Buffer(), videoFrame.Width(), videoFrame.Height(), 0); + break; + case webrtc::kVideoARGB1555 : + convertedFrame.VerifyAndAllocate(webrtc::CalcBufferSize(webrtc::kARGB1555,videoFrame.Width(),videoFrame.Height())); + webrtc::ConvertI420ToARGB1555(videoFrame.Buffer(), convertedFrame.Buffer(), videoFrame.Width(), videoFrame.Height(), 0); + break; + default: + // the format is something funny. Should never reach here... + assert(false); + pConvertedFrame = NULL; + break; + } + + if(_externalRendererWidth!=videoFrame.Width() || _externalRendererHeight!=videoFrame.Height()) + { + _externalRendererWidth = videoFrame.Width(); + _externalRendererHeight = videoFrame.Height(); + _externalRenderer->FrameSizeChange(_externalRendererWidth, _externalRendererHeight, streamId); + } + + if(pConvertedFrame) + { + _externalRenderer->DeliverFrame(pConvertedFrame->Buffer(), pConvertedFrame->Length()); + } + return 0; +} + +} //namespace webrtc + + + + diff --git a/video_engine/main/source/vie_renderer.h b/video_engine/main/source/vie_renderer.h new file mode 100644 index 0000000000..8434aad22d --- /dev/null +++ b/video_engine/main/source/vie_renderer.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_renderer.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RENDERER_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RENDERER_H_ + + +#include "vie_frame_provider_base.h" +#include "map_wrapper.h" +#include "vie_render.h" +#include "video_render_defines.h" + +namespace webrtc { + +class VideoRender; +class VideoRenderCallback; +class ViERenderManager; + + +class ViEExternalRendererImpl : public VideoRenderCallback +{ +public: + ViEExternalRendererImpl(); + int SetViEExternalRenderer(ExternalRenderer* externalRenderer, webrtc::RawVideoType videoInputFormat); + + // implements VideoRenderCallback + virtual WebRtc_Word32 RenderFrame(const WebRtc_UWord32 streamId, + webrtc::VideoFrame& videoFrame); + + virtual ~ViEExternalRendererImpl(){}; + +private: + ExternalRenderer* _externalRenderer; + webrtc::RawVideoType _externalRendererFormat; + WebRtc_UWord32 _externalRendererWidth; + WebRtc_UWord32 _externalRendererHeight; +}; + + +class ViERenderer: public ViEFrameCallback +{ +public: + static ViERenderer* CreateViERenderer(const WebRtc_Word32 renderId, + const WebRtc_Word32 engineId, + VideoRender& renderModule, + ViERenderManager& renderManager, + const WebRtc_UWord32 zOrder, + const float left, + const float top, + const float right, + const float bottom); + + ~ViERenderer(void); + + WebRtc_Word32 StartRender(); + WebRtc_Word32 StopRender(); + + WebRtc_Word32 GetLastRenderedFrame(const WebRtc_Word32 renderID, webrtc::VideoFrame& videoFrame); + + WebRtc_Word32 ConfigureRenderer(const unsigned int zOrder, + const float left, + const float top, + const float right, + const float bottom); + + + VideoRender& RenderModule(); + + WebRtc_Word32 EnableMirroring(const WebRtc_Word32 renderId, const bool enable, const bool mirrorXAxis, const bool mirrorYAxis); + + WebRtc_Word32 SetTimeoutImage(const webrtc::VideoFrame& timeoutImage,const WebRtc_Word32 timeoutValue); + WebRtc_Word32 SetRenderStartImage(const webrtc::VideoFrame& startImage); + WebRtc_Word32 SetExternalRenderer(const WebRtc_Word32 renderId, webrtc::RawVideoType videoInputFormat, ExternalRenderer* externalRenderer); + +private: + WebRtc_Word32 Init(const WebRtc_UWord32 zOrder, + const float left, + const float top, + const float right, + const float bottom); + + ViERenderer(const WebRtc_Word32 renderId,const WebRtc_Word32 engineId, + VideoRender& renderModule, + ViERenderManager& renderManager); + + + // Implement ViEFrameCallback + + virtual void DeliverFrame(int id, VideoFrame& videoFrame, int numCSRCs = 0, + const WebRtc_UWord32 CSRC[kRtpCsrcSize] = NULL); + virtual void DelayChanged(int id, int frameDelay){return;} + virtual int GetPreferedFrameSettings(int &width, int &height, + int &frameRate){return -1;} + + virtual void ProviderDestroyed(int id); + + + WebRtc_UWord32 _renderId; + WebRtc_Word32 _engineId; + VideoRender& _renderModule; + ViERenderManager& _renderManager; + VideoRenderCallback* _ptrRenderCallback; + ViEExternalRendererImpl* _ptrIncomingExternalCallback; + +}; + +} //namespace webrtc + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RENDERER_H_ diff --git a/video_engine/main/source/vie_rtp_rtcp_impl.cc b/video_engine/main/source/vie_rtp_rtcp_impl.cc new file mode 100644 index 0000000000..c4c0f9ff2b --- /dev/null +++ b/video_engine/main/source/vie_rtp_rtcp_impl.cc @@ -0,0 +1,1275 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_rtp_rtcp_impl.cc + */ + +#include "vie_rtp_rtcp_impl.h" + +// Defines +#include "engine_configurations.h" +#include "vie_defines.h" + +#include "vie_errors.h" +#include "file_wrapper.h" +#include "trace.h" +#include "vie_impl.h" +#include "vie_channel.h" +#include "vie_channel_manager.h" +#include "vie_encoder.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// GetInterface +// ---------------------------------------------------------------------------- + +ViERTP_RTCP* ViERTP_RTCP::GetInterface(VideoEngine* videoEngine) +{ +#ifdef WEBRTC_VIDEO_ENGINE_RTP_RTCP_API + if (videoEngine == NULL) + { + return NULL; + } + VideoEngineImpl* vieImpl = reinterpret_cast (videoEngine); + ViERTP_RTCPImpl* vieRTPImpl = vieImpl; + (*vieRTPImpl)++; // Increase ref count + + return vieRTPImpl; +#else + return NULL; +#endif +} + +// ---------------------------------------------------------------------------- +// Release +// +// Releases the interface, i.e. reduces the reference counter. The number of +// remaining references is returned, -1 if released too many times. +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::Release() +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, + "ViERTP_RTCP::Release()"); + (*this)--; // Decrease ref count + + WebRtc_Word32 refCount = GetCount(); + if (refCount < 0) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, + "ViERTP_RTCP release too many times"); + SetLastError(kViEAPIDoesNotExist); + return -1; + } + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId, + "ViERTP_RTCP reference count: %d", refCount); + return refCount; +} + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViERTP_RTCPImpl::ViERTP_RTCPImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViERTP_RTCPImpl::ViERTP_RTCPImpl() Ctor"); +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- + +ViERTP_RTCPImpl::~ViERTP_RTCPImpl() +{ + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, + "ViERTP_RTCPImpl::~ViERTP_RTCPImpl() Dtor"); +} + +// ============================================================================ +// SSRC/CSRC +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetLocalSSRC +// +// Sets the SSRC on the outgoing stream +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::SetLocalSSRC(const int videoChannel, + const unsigned int SSRC) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d, SSRC: %d)", + __FUNCTION__, videoChannel, SSRC); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + if (ptrViEChannel->SetSSRC(SSRC) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// GetLocalSSRC +// +// Gets the SSRC of the outgoing stream +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::GetLocalSSRC(const int videoChannel, + unsigned int& SSRC) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d, SSRC: %d)", + __FUNCTION__, videoChannel, SSRC); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->GetLocalSSRC((WebRtc_UWord32&) SSRC) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; + +} + +// ---------------------------------------------------------------------------- +// GetRemoteSSRC +// +// Gets the SSRC of the incoming stream +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::GetRemoteSSRC(const int videoChannel, + unsigned int& SSRC) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel, SSRC); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->GetRemoteSSRC((WebRtc_UWord32&) SSRC) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetRemoteCSRCs +// +// Gets the CSRC of the incoming stream +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::GetRemoteCSRCs(const int videoChannel, + unsigned int CSRCs[kRtpCsrcSize]) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->GetRemoteCSRC(CSRCs) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// SetStartSequenceNumber +// +// Sets the starting sequence number, instead of a random number. +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::SetStartSequenceNumber(const int videoChannel, + unsigned short sequenceNumber) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, sequenceNumber: %u)", __FUNCTION__, + videoChannel, sequenceNumber); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + if (ptrViEChannel->Sending()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d already sending.", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpAlreadySending); + return -1; + } + + if (ptrViEChannel->SetStartSequenceNumber(sequenceNumber) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// RTCP +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetRTCPStatus +// +// Sets the RTCP status for the channel +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::SetRTCPStatus(const int videoChannel, + const ViERTCPMode rtcpMode) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId,videoChannel), "%s(channel: %d, mode: %d)", + __FUNCTION__, videoChannel, rtcpMode); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + RTCPMethod moduleMode = ViERTCPModeToRTCPMethod(rtcpMode); + + if (ptrViEChannel->SetRTCPMode(moduleMode) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; + +} + +// ---------------------------------------------------------------------------- +// GetRTCPStatus +// +// Gets the RTCP status for the specified channel +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::GetRTCPStatus(const int videoChannel, + ViERTCPMode& rtcpMode) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel, rtcpMode); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + RTCPMethod moduleMode = kRtcpOff; + if (ptrViEChannel->GetRTCPMode(moduleMode) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: could not get current RTCP mode", __FUNCTION__); + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + + rtcpMode = RTCPMethodToViERTCPMode(moduleMode); + return 0; +} + +// ---------------------------------------------------------------------------- +// SetRTCPCName +// +// Specifies what CName to use +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::SetRTCPCName(const int videoChannel, + const char rtcpCName[KMaxRTCPCNameLength]) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d, name: %s)", + __FUNCTION__, videoChannel, rtcpCName); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->Sending()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d already sending.", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpAlreadySending); + return -1; + } + + if (ptrViEChannel->SetRTCPCName(rtcpCName) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; + +} + +// ---------------------------------------------------------------------------- +// GetRTCPCName +// +// Gets the set CName +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::GetRTCPCName(const int videoChannel, + char rtcpCName[KMaxRTCPCNameLength]) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + if (ptrViEChannel->GetRTCPCName(rtcpCName) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; + +} + +// ---------------------------------------------------------------------------- +// GetRemoteRTCPCName +// +// Gets the CName of for the incoming stream +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::GetRemoteRTCPCName(const int videoChannel, + char rtcpCName[KMaxRTCPCNameLength]) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + if (ptrViEChannel->GetRemoteRTCPCName(rtcpCName) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// SendApplicationDefinedRTCPPacket +// +// From RFC 3550: +// +// 6.7 APP: Application-Defined RTCP Packet +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| subtype | PT=APP=204 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC/CSRC | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | name (ASCII) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | application-dependent data ... +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// The APP packet is intended for experimental use as new applications +// and new features are developed, without requiring packet type value +// registration. APP packets with unrecognized names SHOULD be ignored. +// After testing and if wider use is justified, it is RECOMMENDED that +// each APP packet be redefined without the subtype and name fields and +// registered with IANA using an RTCP packet type. +// +// version (V), padding (P), length: +// As described for the SR packet (see Section 6.4.1). +// +// subtype: 5 bits +// May be used as a subtype to allow a set of APP packets to be +// defined under one unique name, or for any application-dependent +// data. +// +// packet type (PT): 8 bits +// Contains the constant 204 to identify this as an RTCP APP packet. +// +// name: 4 octets +// A name chosen by the person defining the set of APP packets to be +// unique with respect to other APP packets this application might +// receive. The application creator might choose to use the +// application name, and then coordinate the allocation of subtype +// values to others who want to define new packet types for the +// application. Alternatively, it is RECOMMENDED that others choose +// a name based on the entity they represent, then coordinate the use +// of the name within that entity. The name is interpreted as a +// sequence of four ASCII characters, with uppercase and lowercase +// characters treated as distinct. +// +// application-dependent data: variable length +// Application-dependent data may or may not appear in an APP packet. +// It is interpreted by the application and not RTP itself. It MUST +// be a multiple of 32 bits long. +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::SendApplicationDefinedRTCPPacket( + const int videoChannel, const unsigned char subType, unsigned int name, + const char* data, unsigned short dataLengthInBytes) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, subType: %c, name: %d, data: x, length: %u)", + __FUNCTION__, videoChannel, subType, name, dataLengthInBytes); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + if (!ptrViEChannel->Sending()) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d not sending", __FUNCTION__, videoChannel); + SetLastError(kViERtpRtcpNotSending); + return -1; + } + RTCPMethod method; + if (ptrViEChannel->GetRTCPMode(method) != 0 || method == kRtcpOff) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: RTCP disabled on channel %d.", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpRtcpDisabled); + return -1; + } + + if (ptrViEChannel->SendApplicationDefinedRTCPPacket( + subType, name, (const WebRtc_UWord8 *) data, dataLengthInBytes) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// SetNACKStatus +// +// Enables NACK for the specified channel +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::SetNACKStatus(const int videoChannel, const bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, enable: %d)", __FUNCTION__, videoChannel, + enable); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + // Update the channel status + if (ptrViEChannel->SetNACKStatus(enable) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: failed for channel %d", __FUNCTION__, videoChannel); + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + + // Update the encoder + ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel); + if (ptrViEEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Could not get encoder for channel %d", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + ptrViEEncoder->UpdateProtectionMethod(); + + return 0; +} + +// ---------------------------------------------------------------------------- +// SetFECStatus +// +// Enables/disables FEC and sets the payloadtypes +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::SetFECStatus(const int videoChannel, const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, enable: %d, payloadTypeRED: %u, " + "payloadTypeFEC: %u)", + __FUNCTION__, videoChannel, enable, payloadTypeRED, + payloadTypeFEC); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + // Update the channel status + if (ptrViEChannel->SetFECStatus(enable, payloadTypeRED, payloadTypeFEC) + != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: failed for channel %d", __FUNCTION__, videoChannel); + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + + // Update the encoder + ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel); + if (ptrViEEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Could not get encoder for channel %d", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + ptrViEEncoder->UpdateProtectionMethod(); + return 0; +} + +// ---------------------------------------------------------------------------- +// SetKeyFrameRequestMethod +// +// Sets the key frame request method to use +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::SetKeyFrameRequestMethod( + const int videoChannel, const ViEKeyFrameRequestMethod method) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, method: %d)", __FUNCTION__, videoChannel, + method); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + KeyFrameRequestMethod moduleMethod = APIRequestToModuleRequest(method); + if (ptrViEChannel->SetKeyFrameRequestMethod(moduleMethod) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// SetTMMBRStatus +// +// Enables/disables TTMBR +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::SetTMMBRStatus(const int videoChannel, const bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, enable: %d)", __FUNCTION__, videoChannel, + enable); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->EnableTMMBR(enable) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// Statistics +// ============================================================================ + +// ---------------------------------------------------------------------------- +// GetReceivedRTCPStatistics +// +// Gets statistics received in from remote side +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::GetReceivedRTCPStatistics( + const int videoChannel, unsigned short& fractionLost, + unsigned int& cumulativeLost, unsigned int& extendedMax, + unsigned int& jitter, int& rttMs) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->GetReceivedRtcpStatistics( + (WebRtc_UWord16&) fractionLost, (WebRtc_UWord32&) cumulativeLost, + (WebRtc_UWord32&) extendedMax, (WebRtc_UWord32&) jitter, + (WebRtc_Word32&) rttMs) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetSentRTCPStatistics +// +// Gets statistics sent in RTCP to the remote side +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::GetSentRTCPStatistics(const int videoChannel, + unsigned short& fractionLost, + unsigned int& cumulativeLost, + unsigned int& extendedMax, + unsigned int& jitter, + int& rttMs) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->GetSendRtcpStatistics((WebRtc_UWord16&) fractionLost, + (WebRtc_UWord32&) cumulativeLost, + (WebRtc_UWord32&) extendedMax, + (WebRtc_UWord32&) jitter, + (WebRtc_Word32&) rttMs) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetRTCPStatistics +// +// Gets statistics about sent/received rtp packets +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::GetRTPStatistics(const int videoChannel, + unsigned int& bytesSent, + unsigned int& packetsSent, + unsigned int& bytesReceived, + unsigned int& packetsReceived) const +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->GetRtpStatistics((WebRtc_UWord32&) bytesSent, + (WebRtc_UWord32&) packetsSent, + (WebRtc_UWord32&) bytesReceived, + (WebRtc_UWord32&) packetsReceived) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// Keep alive +// ============================================================================ + +// ---------------------------------------------------------------------------- +// SetRTPKeepAliveStatus +// +// Enable/disable RTP keepaliv packets on a non-sending channel +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::SetRTPKeepAliveStatus( + const int videoChannel, bool enable, const char unknownPayloadType, + const unsigned int deltaTransmitTimeSeconds) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, enable: %d, unknownPayloadType: %d, " + "deltaTransmitTimeMS: %ul)", + __FUNCTION__, videoChannel, enable, (int) unknownPayloadType, + deltaTransmitTimeSeconds); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + WebRtc_UWord16 deltaTransmitTimeMs = 1000 * deltaTransmitTimeSeconds; + if (ptrViEChannel->SetKeepAliveStatus(enable, unknownPayloadType, + deltaTransmitTimeMs) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GetRTPKeepAliveStatus +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::GetRTPKeepAliveStatus( + const int videoChannel, bool& enabled, char& unknownPayloadType, + unsigned int& deltaTransmitTimeSeconds) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + WebRtc_UWord16 deltaTimeMs = 0; + int retVal = ptrViEChannel->GetKeepAliveStatus(enabled, unknownPayloadType, + deltaTimeMs); + deltaTransmitTimeSeconds = deltaTimeMs / 1000; + if (retVal != 0) + { + SetLastError(kViERtpRtcpUnknownError); + } + return retVal; +} + +// ============================================================================ +// Dump RTP stream, for debug purpose +// ============================================================================ + +// ---------------------------------------------------------------------------- +// StartRTPDump +// +// SAves all incoming/outgoing packets to a file +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::StartRTPDump(const int videoChannel, + const char fileNameUTF8[1024], + RTPDirections direction) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, fileName: %s, direction: %d)", __FUNCTION__, + videoChannel, fileNameUTF8, direction); + + assert(FileWrapper::kMaxFileNameSize == 1024); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->StartRTPDump(fileNameUTF8, direction) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// StopRTPDump +// +// Stops the RTP dump +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::StopRTPDump(const int videoChannel, + RTPDirections direction) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, direction: %d)", __FUNCTION__, videoChannel, + direction); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->StopRTPDump(direction) != 0) + { + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +// ============================================================================ +// Callback +// ============================================================================ + +// ---------------------------------------------------------------------------- +// RegisterRTPObserver +// +// +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::RegisterRTPObserver(const int videoChannel, + ViERTPObserver& observer) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->RegisterRtpObserver(&observer) != 0) + { + SetLastError(kViERtpRtcpObserverAlreadyRegistered); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterRTPObserver +// +// Deregisters a set observer +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::DeregisterRTPObserver(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->RegisterRtpObserver(NULL) != 0) + { + SetLastError(kViERtpRtcpObserverNotRegistered); + return -1; + } + return 0; +} +// ---------------------------------------------------------------------------- +// RegisterRTCPObserver +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::RegisterRTCPObserver(const int videoChannel, + ViERTCPObserver& observer) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + if (ptrViEChannel->RegisterRtcpObserver(&observer) != 0) + { + SetLastError(kViERtpRtcpObserverAlreadyRegistered); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterRTCPObserver +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::DeregisterRTCPObserver(const int videoChannel) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), "%s(channel: %d)", + __FUNCTION__, videoChannel); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + + } + + if (ptrViEChannel->RegisterRtcpObserver(NULL) != 0) + { + SetLastError(kViERtpRtcpObserverNotRegistered); + return -1; + } + return 0; +} + +// ============================================================================ +// Prsivate methods +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ViERTCPModeToRTCPMethod +// +// Help method for converting API mode to Module mode +// ---------------------------------------------------------------------------- + +RTCPMethod ViERTP_RTCPImpl::ViERTCPModeToRTCPMethod(ViERTCPMode apiMode) +{ + switch (apiMode) + { + case kRtcpNone: + return kRtcpOff; + + case kRtcpCompound_RFC4585: + return kRtcpCompound; + + case kRtcpNonCompound_RFC5506: + return kRtcpNonCompound; + + default: + assert(false); + return kRtcpOff; + } +} + +// ---------------------------------------------------------------------------- +// RTCPMethodToViERTCPMode +// +// Help method for converting API mode to Module mode +// ---------------------------------------------------------------------------- + +ViERTCPMode ViERTP_RTCPImpl::RTCPMethodToViERTCPMode(RTCPMethod moduleMethod) +{ + switch (moduleMethod) + { + case kRtcpOff: + return kRtcpNone; + + case kRtcpCompound: + return kRtcpCompound_RFC4585; + + case kRtcpNonCompound: + return kRtcpNonCompound_RFC5506; + + default: + assert(false); + return kRtcpNone; + } +} + +KeyFrameRequestMethod ViERTP_RTCPImpl::APIRequestToModuleRequest( + ViEKeyFrameRequestMethod apiMethod) +{ + switch (apiMethod) + { + case kViEKeyFrameRequestNone: + return kKeyFrameReqFirRtp; + + case kViEKeyFrameRequestPliRtcp: + return kKeyFrameReqPliRtcp; + + case kViEKeyFrameRequestFirRtp: + return kKeyFrameReqFirRtp; + + case kViEKeyFrameRequestFirRtcp: + return kKeyFrameReqFirRtcp; + + default: + assert(false); + return kKeyFrameReqFirRtp; + } +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_rtp_rtcp_impl.h b/video_engine/main/source/vie_rtp_rtcp_impl.h new file mode 100644 index 0000000000..8c429ed3b7 --- /dev/null +++ b/video_engine/main/source/vie_rtp_rtcp_impl.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_rtp_rtcp_impl.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RTP_RTCP_IMPL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RTP_RTCP_IMPL_H_ + +#include "vie_defines.h" + +#include "rtp_rtcp_defines.h" +#include "typedefs.h" +#include "vie_ref_count.h" +#include "vie_rtp_rtcp.h" +#include "vie_shared_data.h" + +namespace webrtc +{ + +// ---------------------------------------------------------------------------- +// ViERTP_RTCPImpl +// ---------------------------------------------------------------------------- + +class ViERTP_RTCPImpl : public virtual ViESharedData, + public ViERTP_RTCP, + public ViERefCount +{ +public: + virtual int Release(); + + // SSRC/CSRC + virtual int SetLocalSSRC(const int videoChannel, const unsigned int SSRC); + + virtual int GetLocalSSRC(const int videoChannel, unsigned int& SSRC) const; + + virtual int GetRemoteSSRC(const int videoChannel, unsigned int& SSRC) const; + + virtual int GetRemoteCSRCs(const int videoChannel, + unsigned int CSRCs[kRtpCsrcSize]) const; + + virtual int SetStartSequenceNumber(const int videoChannel, + unsigned short sequenceNumber); + + // RTCP + virtual int SetRTCPStatus(const int videoChannel, + const ViERTCPMode rtcpMode); + + virtual int GetRTCPStatus(const int videoChannel, ViERTCPMode& rtcpMode); + + virtual int SetRTCPCName(const int videoChannel, + const char rtcpCName[KMaxRTCPCNameLength]); + + virtual int GetRTCPCName(const int videoChannel, + char rtcpCName[KMaxRTCPCNameLength]); + + virtual int GetRemoteRTCPCName(const int videoChannel, + char rtcpCName[KMaxRTCPCNameLength]) const; + + virtual int + SendApplicationDefinedRTCPPacket(const int videoChannel, + const unsigned char subType, + unsigned int name, const char* data, + unsigned short dataLengthInBytes); + + virtual int SetNACKStatus(const int videoChannel, const bool enable); + + virtual int SetFECStatus(const int videoChannel, const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC); + + virtual int SetKeyFrameRequestMethod(const int videoChannel, + const ViEKeyFrameRequestMethod method); + + virtual int SetTMMBRStatus(const int videoChannel, const bool enable); + + // Statistics + virtual int GetReceivedRTCPStatistics( + const int videoChannel, unsigned short& fractionLost, + unsigned int& cumulativeLost, unsigned int& extendedMax, + unsigned int& jitter, int& rttMs) const; + + virtual int GetSentRTCPStatistics(const int videoChannel, + unsigned short& fractionLost, + unsigned int& cumulativeLost, + unsigned int& extendedMax, + unsigned int& jitter, int& rttMs) const; + + virtual int GetRTPStatistics(const int videoChannel, + unsigned int& bytesSent, + unsigned int& packetsSent, + unsigned int& bytesReceived, + unsigned int& packetsReceived) const; + + // Keep alive + virtual int SetRTPKeepAliveStatus( + const int videoChannel, bool enable, const char unknownPayloadType, + const unsigned int deltaTransmitTimeSeconds); + + virtual int GetRTPKeepAliveStatus(const int videoChannel, bool& enabled, + char& unkownPayloadType, + unsigned int& deltaTransmitTimeSeconds); + + // Dump RTP stream, for debug purpose + virtual int StartRTPDump(const int videoChannel, + const char fileNameUTF8[1024], + RTPDirections direction); + + virtual int StopRTPDump(const int videoChannel, RTPDirections direction); + + // Callbacks + virtual int RegisterRTPObserver(const int videoChannel, + ViERTPObserver& observer); + + virtual int DeregisterRTPObserver(const int videoChannel); + + virtual int RegisterRTCPObserver(const int videoChannel, + ViERTCPObserver& observer); + + virtual int DeregisterRTCPObserver(const int videoChannel); + +protected: + ViERTP_RTCPImpl(); + virtual ~ViERTP_RTCPImpl(); + +private: + RTCPMethod ViERTCPModeToRTCPMethod(ViERTCPMode apiMode); + ViERTCPMode RTCPMethodToViERTCPMode(RTCPMethod moduleMethod); + KeyFrameRequestMethod + APIRequestToModuleRequest(const ViEKeyFrameRequestMethod apiMethod); +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_RTP_RTCP_IMPL_H_ diff --git a/video_engine/main/source/vie_sender.cc b/video_engine/main/source/vie_sender.cc new file mode 100644 index 0000000000..3315f4db68 --- /dev/null +++ b/video_engine/main/source/vie_sender.cc @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_sender.cc + */ + +#include "vie_sender.h" + +#include "critical_section_wrapper.h" +#include "rtp_rtcp.h" +#ifdef WEBRTC_SRTP +#include "SrtpModule.h" +#endif +#include "rtp_dump.h" +#include "trace.h" + +namespace webrtc { + +// ---------------------------------------------------------------------------- +// Constructor +// ---------------------------------------------------------------------------- + +ViESender::ViESender(int engineId, int channelId, + RtpRtcp& rtpRtcpModule) + : _engineId(engineId), _channelId(channelId), + _sendCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _rtpRtcp(rtpRtcpModule), +#ifdef WEBRTC_SRTP + _ptrSrtp(NULL), + _ptrSrtcp(NULL), +#endif + _ptrExternalEncryption(NULL), _ptrSrtpBuffer(NULL), + _ptrSrtcpBuffer(NULL), _ptrEncryptionBuffer(NULL), _ptrTransport(NULL), + _rtpDump(NULL) +{ +} + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- +ViESender::~ViESender() +{ + delete &_sendCritsect; + + if (_ptrSrtpBuffer) + { + delete[] _ptrSrtpBuffer; + _ptrSrtpBuffer = NULL; + } + if (_ptrSrtcpBuffer) + { + delete[] _ptrSrtcpBuffer; + _ptrSrtcpBuffer = NULL; + } + if (_ptrEncryptionBuffer) + { + delete[] _ptrEncryptionBuffer; + _ptrEncryptionBuffer = NULL; + } + if (_rtpDump) + { + _rtpDump->Stop(); + RtpDump::DestroyRtpDump(_rtpDump); + _rtpDump = NULL; + } +} + +// ---------------------------------------------------------------------------- +// RegisterExternalEncryption +// ---------------------------------------------------------------------------- + +int ViESender::RegisterExternalEncryption(Encryption* encryption) +{ + CriticalSectionScoped cs(_sendCritsect); + if (_ptrExternalEncryption) + { + return -1; + } + _ptrEncryptionBuffer = new WebRtc_UWord8[kViEMaxMtu]; + if (_ptrEncryptionBuffer == NULL) + { + return -1; + } + _ptrExternalEncryption = encryption; + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterExternalEncryption +// ---------------------------------------------------------------------------- + +int ViESender::DeregisterExternalEncryption() +{ + CriticalSectionScoped cs(_sendCritsect); + if (_ptrExternalEncryption == NULL) + { + return -1; + } + if (_ptrEncryptionBuffer) + { + delete _ptrEncryptionBuffer; + _ptrEncryptionBuffer = NULL; + } + _ptrExternalEncryption = NULL; + return 0; +} + +// ---------------------------------------------------------------------------- +// RegisterSendTransport +// ---------------------------------------------------------------------------- + +int ViESender::RegisterSendTransport(Transport* transport) +{ + CriticalSectionScoped cs(_sendCritsect); + if (_ptrTransport) + { + return -1; + } + _ptrTransport = transport; + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterSendTransport +// ---------------------------------------------------------------------------- + +int ViESender::DeregisterSendTransport() +{ + CriticalSectionScoped cs(_sendCritsect); + if (_ptrTransport == NULL) + { + return -1; + } + _ptrTransport = NULL; + return 0; +} + +#ifdef WEBRTC_SRTP +// ---------------------------------------------------------------------------- +// RegisterSRTPModule +// ---------------------------------------------------------------------------- + +int ViESender::RegisterSRTPModule(SrtpModule* srtpModule) +{ + CriticalSectionScoped cs(_sendCritsect); + if (_ptrSrtp || + srtpModule == NULL) + { + return -1; + } + _ptrSrtpBuffer = new WebRtc_UWord8[KMaxPacketSize]; + if (_ptrSrtpBuffer == NULL) + { + return -1; + } + _ptrSrtp = srtpModule; + + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterSRTPModule +// ---------------------------------------------------------------------------- + +int ViESender::DeregisterSRTPModule() +{ + CriticalSectionScoped cs(_sendCritsect); + if (_ptrSrtp == NULL) + { + return -1; + } + if (_ptrSrtpBuffer) + { + delete [] _ptrSrtpBuffer; + _ptrSrtpBuffer = NULL; + } + _ptrSrtp = NULL; + return 0; +} +// ---------------------------------------------------------------------------- +// RegisterSRTCPModule +// ---------------------------------------------------------------------------- + +int ViESender::RegisterSRTCPModule(SrtpModule* srtcpModule) +{ + CriticalSectionScoped cs(_sendCritsect); + if (_ptrSrtcp || + srtcpModule == NULL) + { + return -1; + } + _ptrSrtcpBuffer = new WebRtc_UWord8[KMaxPacketSize]; + if (_ptrSrtcpBuffer == NULL) + { + return -1; + } + _ptrSrtcp = srtcpModule; + + return 0; +} + +// ---------------------------------------------------------------------------- +// DeregisterSRTCPModule +// ---------------------------------------------------------------------------- + +int ViESender::DeregisterSRTCPModule() +{ + CriticalSectionScoped cs(_sendCritsect); + if (_ptrSrtcp == NULL) + { + return -1; + } + if (_ptrSrtcpBuffer) + { + delete [] _ptrSrtcpBuffer; + _ptrSrtcpBuffer = NULL; + } + _ptrSrtcp = NULL; + return 0; +} +#endif + +// ---------------------------------------------------------------------------- +// StartRTPDump +// ---------------------------------------------------------------------------- + +int ViESender::StartRTPDump(const char fileNameUTF8[1024]) +{ + CriticalSectionScoped cs(_sendCritsect); + if (_rtpDump) + { + // Restart it if it already exists and is started + _rtpDump->Stop(); + } else + { + _rtpDump = RtpDump::CreateRtpDump(); + if (_rtpDump == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: Failed to create RTP dump", __FUNCTION__); + return -1; + } + } + if (_rtpDump->Start(fileNameUTF8) != 0) + { + RtpDump::DestroyRtpDump(_rtpDump); + _rtpDump = NULL; + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Failed to start RTP dump", __FUNCTION__); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// StopRTPDump +// ---------------------------------------------------------------------------- + +int ViESender::StopRTPDump() +{ + CriticalSectionScoped cs(_sendCritsect); + if (_rtpDump) + { + if (_rtpDump->IsActive()) + { + _rtpDump->Stop(); + } else + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, + _channelId), + "%s: Dump not active", __FUNCTION__); + } + RtpDump::DestroyRtpDump(_rtpDump); + _rtpDump = NULL; + } else + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), "%s: RTP dump not started", + __FUNCTION__); + return -1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// SendPacket +// ---------------------------------------------------------------------------- +int ViESender::SendPacket(int vieId, const void *data, int len) +{ + CriticalSectionScoped cs(_sendCritsect); + if (!_ptrTransport) + { + // No transport + return -1; + } + + int channelId = ChannelId(vieId); + assert(channelId == _channelId); + + // Prepare for possible encryption and sending + WebRtc_UWord8* sendPacket = (WebRtc_UWord8*) data; + int sendPacketLength = len; + + if (_rtpDump) + { + _rtpDump->DumpPacket(sendPacket, sendPacketLength); + } +#ifdef WEBRTC_SRTP + if (_ptrSrtp) + { + _ptrSrtp->encrypt(_channelId, sendPacket, _ptrSrtpBuffer, sendPacketLength, (int*) &sendPacketLength); + if (sendPacketLength <= 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "RTP encryption failed for channel"); + return -1; + } + else if (sendPacketLength > KMaxPacketSize) + { + WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, ViEId(_engineId, _channelId), + " %d bytes is allocated as RTP output => memory is now corrupted", KMaxPacketSize); + return -1; + } + sendPacket = _ptrSrtpBuffer; + } +#endif + if (_ptrExternalEncryption) + { + _ptrExternalEncryption->encrypt(_channelId, sendPacket, + _ptrEncryptionBuffer, sendPacketLength, + (int*) &sendPacketLength); + sendPacket = _ptrEncryptionBuffer; + } + + return _ptrTransport->SendPacket(_channelId, sendPacket, sendPacketLength); +} +// ---------------------------------------------------------------------------- +// SendRTCPPacket +// ---------------------------------------------------------------------------- + +int ViESender::SendRTCPPacket(int vieId, const void *data, int len) +{ + CriticalSectionScoped cs(_sendCritsect); + + if (!_ptrTransport) + { + // No transport + return -1; + } + int channelId = ChannelId(vieId); + assert(channelId == _channelId); + + // Prepare for possible encryption and sending + WebRtc_UWord8* sendPacket = (WebRtc_UWord8*) data; + int sendPacketLength = len; + + if (_rtpDump) + { + _rtpDump->DumpPacket(sendPacket, sendPacketLength); + } +#ifdef WEBRTC_SRTP + if (_ptrSrtcp) + { + _ptrSrtcp->encrypt_rtcp(_channelId, sendPacket, _ptrSrtcpBuffer, sendPacketLength, (int*) &sendPacketLength); + if (sendPacketLength <= 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "RTCP encryption failed for channel"); + return -1; + } + else if (sendPacketLength > KMaxPacketSize) + { + WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, ViEId(_engineId, _channelId), " %d bytes is allocated as RTCP output => memory is now corrupted", KMaxPacketSize); + return -1; + } + sendPacket = _ptrSrtcpBuffer; + } +#endif + if (_ptrExternalEncryption) + { + _ptrExternalEncryption->encrypt_rtcp(_channelId, sendPacket, + _ptrEncryptionBuffer, + sendPacketLength, + (int*) &sendPacketLength); + sendPacket = _ptrEncryptionBuffer; + } + + return _ptrTransport->SendRTCPPacket(_channelId, sendPacket, + sendPacketLength); +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_sender.h b/video_engine/main/source/vie_sender.h new file mode 100644 index 0000000000..4d6726710f --- /dev/null +++ b/video_engine/main/source/vie_sender.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_sender.h + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_SENDER_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_SENDER_H_ + +// Defines +#include "engine_configurations.h" +#include "vie_defines.h" +#include "typedefs.h" +#include "common_types.h" + +// Forward declarations + +#ifdef WEBRTC_SRTP + class SrtpModule; +#endif + +namespace webrtc { +class CriticalSectionWrapper; +class RtpDump; +class RtpRtcp; +class Transport; +class VideoCodingModule; + +class ViESender: public Transport +{ +public: + ViESender(int engineId, int channelId, RtpRtcp& rtpRtcpModule); + ~ViESender(); + + int RegisterExternalEncryption(Encryption* encryption); + int DeregisterExternalEncryption(); + + int RegisterSendTransport(Transport* transport); + int DeregisterSendTransport(); + +#ifdef WEBRTC_SRTP + int RegisterSRTPModule(SrtpModule* srtpModule); + int DeregisterSRTPModule(); + + int RegisterSRTCPModule(SrtpModule* srtpModule); + int DeregisterSRTCPModule(); +#endif + + int StartRTPDump(const char fileNameUTF8[1024]); + int StopRTPDump(); + + // Implements Transport + virtual int SendPacket(int vieId, const void *data, int len); + virtual int SendRTCPPacket(int vieId, const void *data, int len); + +private: + int _engineId; + int _channelId; + CriticalSectionWrapper& _sendCritsect; + RtpRtcp& _rtpRtcp; + +#ifdef WEBRTC_SRTP + SrtpModule* _ptrSrtp; + SrtpModule* _ptrSrtcp; +#endif + + Encryption* _ptrExternalEncryption; + WebRtc_UWord8* _ptrSrtpBuffer; + WebRtc_UWord8* _ptrSrtcpBuffer; + WebRtc_UWord8* _ptrEncryptionBuffer; + Transport* _ptrTransport; + RtpDump* _rtpDump; +}; + +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_SENDER_H_ diff --git a/video_engine/main/source/vie_shared_data.cc b/video_engine/main/source/vie_shared_data.cc new file mode 100644 index 0000000000..800a9b827e --- /dev/null +++ b/video_engine/main/source/vie_shared_data.cc @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// ViESharedData.cpp + +#include "vie_shared_data.h" +#include "vie_defines.h" + +#include "cpu_wrapper.h" +#include "critical_section_wrapper.h" +#include "process_thread.h" +#include "trace.h" +#include "vie_channel_manager.h" +#include "vie_input_manager.h" +#include "vie_render_manager.h" + +namespace webrtc { + +// Active instance counter +int ViESharedData::_instanceCounter = 0; + +ViESharedData::ViESharedData() + : _instanceId(++_instanceCounter), + _apiCritsect(*CriticalSectionWrapper::CreateCriticalSection()), + _isInitialized(false), _numberOfCores(CpuWrapper::DetectNumberOfCores()), + _moduleProcessThreadPtr(ProcessThread::CreateProcessThread()), + _viePerformanceMonitor(ViEPerformanceMonitor(_instanceId)), + _channelManager(*new ViEChannelManager(_instanceId, _numberOfCores, + _viePerformanceMonitor)), + _inputManager(*new ViEInputManager(_instanceId)), + _renderManager(*new ViERenderManager(_instanceId)), _lastError(0) +{ + Trace::CreateTrace(); + _channelManager.SetModuleProcessThread(*_moduleProcessThreadPtr); + _inputManager.SetModuleProcessThread(*_moduleProcessThreadPtr); + _moduleProcessThreadPtr->Start(); +} + +ViESharedData::~ViESharedData() +{ + delete &_inputManager; + delete &_channelManager; + delete &_renderManager; + + _moduleProcessThreadPtr->Stop(); + ProcessThread::DestroyProcessThread(_moduleProcessThreadPtr); + delete &_apiCritsect; + Trace::ReturnTrace(); +} + +bool ViESharedData::IsInitialized() const +{ + return _isInitialized; +} + +int ViESharedData::SetInitialized() +{ + _isInitialized = true; + return 0; +} + +int ViESharedData::SetUnInitialized() +{ + _isInitialized = false; + return 0; +} + +void ViESharedData::SetLastError(const int error) const +{ + _lastError = error; +} + +int ViESharedData::LastErrorInternal() const +{ + int error = _lastError; + _lastError = 0; + return error; +} + +int ViESharedData::NumberOfCores() const +{ + return _numberOfCores; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_shared_data.h b/video_engine/main/source/vie_shared_data.h new file mode 100644 index 0000000000..ec3d83fbe6 --- /dev/null +++ b/video_engine/main/source/vie_shared_data.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// vie_shared_data.h + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_SHARED_DATA_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_SHARED_DATA_H_ + +#include "vie_defines.h" +#include "vie_performance_monitor.h" + +namespace webrtc { +class CriticalSectionWrapper; +class ViERenderManager; +class ViEChannelManager; +class ViEInputManager; +class ProcessThread; + +class ViESharedData +{ +protected: + ViESharedData(); + ~ViESharedData(); + + bool IsInitialized() const; + int SetInitialized(); + int SetUnInitialized(); + void SetLastError(const int error) const; + int LastErrorInternal() const; +protected: + int NumberOfCores() const; + + static int _instanceCounter; + const int _instanceId; + CriticalSectionWrapper& _apiCritsect; + bool _isInitialized; + const int _numberOfCores; + + ViEPerformanceMonitor _viePerformanceMonitor; + ViEChannelManager& _channelManager; + ViEInputManager& _inputManager; + ViERenderManager& _renderManager; + ProcessThread* _moduleProcessThreadPtr; +private: + mutable int _lastError; +}; +} // namespace webrtc + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_SHARED_DATA_H_ diff --git a/video_engine/main/source/vie_sync_module.cc b/video_engine/main/source/vie_sync_module.cc new file mode 100644 index 0000000000..ccddab8c83 --- /dev/null +++ b/video_engine/main/source/vie_sync_module.cc @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vie_sync_module.h" +#include "critical_section_wrapper.h" +#include "voe_video_sync.h" +#include "rtp_rtcp.h" +#include "trace.h" +#include "video_coding.h" + +namespace webrtc { + +ViESyncModule::ViESyncModule(int id, VideoCodingModule& vcm, + RtpRtcp& rtcpModule) + : _dataCritsect(*CriticalSectionWrapper::CreateCriticalSection()), _id(id), + _vcm(vcm), _rtcpModule(rtcpModule), _voiceChannelId(-1), + _voiceSyncInterface(NULL), _lastSyncTime(TickTime::Now()) +{ +} + +ViESyncModule::~ViESyncModule() +{ + delete &_dataCritsect; +} + +int ViESyncModule::SetVoiceChannel(int voiceChannelId, + VoEVideoSync* veSyncInterface) +{ + CriticalSectionScoped cs(_dataCritsect); + _voiceChannelId = voiceChannelId; + _voiceSyncInterface = veSyncInterface; + _rtcpModule.DeRegisterSyncModule(); + + if (!veSyncInterface) + { + _voiceChannelId = -1; + if (voiceChannelId >= 0) // trying to set a voice channel but no interface exist + { + return -1; + } + return 0; + } + RtpRtcp* voiceRTPRTCP = NULL; + veSyncInterface->GetRtpRtcp(_voiceChannelId, voiceRTPRTCP); + return _rtcpModule.RegisterSyncModule(voiceRTPRTCP); +} + +int ViESyncModule::VoiceChannel() +{ + return _voiceChannelId; +} + +// ---------------------------------------------------------------------------- +// SetNetworkDelay +// +// Set how long time in ms voice is ahead of video when received on the network. +// Positive means audio is ahead of video. +// ---------------------------------------------------------------------------- +void ViESyncModule::SetNetworkDelay(int networkDelay) +{ + _channelDelay.networkDelay = networkDelay; +} + +// Implements Module +WebRtc_Word32 ViESyncModule::Version(WebRtc_Word8* version, + WebRtc_UWord32& remainingBufferInBytes, + WebRtc_UWord32& position) const +{ + if (version == NULL) + { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, -1, + "Invalid in argument to ViESyncModule Version()"); + return -1; + } + WebRtc_Word8 ourVersion[] = "ViESyncModule 1.1.0"; + WebRtc_UWord32 ourLength = (WebRtc_UWord32) strlen(ourVersion); + if (remainingBufferInBytes < ourLength + 1) + { + return -1; + } + memcpy(version, ourVersion, ourLength); + version[ourLength] = '\0'; // null terminaion + remainingBufferInBytes -= (ourLength + 1); + position += (ourLength + 1); + return 0; +} + +WebRtc_Word32 ViESyncModule::ChangeUniqueId(const WebRtc_Word32 id) +{ + _id = id; + return 0; +} + +WebRtc_Word32 ViESyncModule::TimeUntilNextProcess() +{ + return (WebRtc_Word32) (kSyncInterval - (TickTime::Now() + - _lastSyncTime).Milliseconds()); +} + +// Do the lip sync. +WebRtc_Word32 ViESyncModule::Process() +{ + CriticalSectionScoped cs(_dataCritsect); + _lastSyncTime = TickTime::Now(); + + int totalVideoDelayTargetMS = _vcm.Delay(); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _id, + "Video delay (JB + decoder) is %d ms", totalVideoDelayTargetMS); + + if (_voiceChannelId != -1) + { + // Get //Sync start + int currentAudioDelayMS = 0; + if (_voiceSyncInterface->GetDelayEstimate(_voiceChannelId, + currentAudioDelayMS) != 0) + { + // Could not get VoE delay value, probably not a valid channel Id. + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, _id, + "%s: VE_GetDelayEstimate error for voiceChannel %d", + __FUNCTION__, totalVideoDelayTargetMS, _voiceChannelId); + return 0; + } + int currentDiffMS = 0; + int videoDelayMS = 0; // Total video delay + if (currentAudioDelayMS > 40) // Voice Engine report delay estimates even when not started. Ignore + { + + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _id, + "Audio delay is: %d for voice channel: %d", + currentAudioDelayMS, _voiceChannelId); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _id, + "Network delay diff is: %d for voice channel: %d", + _channelDelay.networkDelay, _voiceChannelId); + // Calculate the diff between the lowest possible + // video delay and the current audio delay + currentDiffMS = totalVideoDelayTargetMS - currentAudioDelayMS + + _channelDelay.networkDelay; + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _id, + "Current diff is: %d for audio channel: %d", + currentDiffMS, _voiceChannelId); + + if (currentDiffMS > 0) + { + // The minimum video delay is longer than the current audio delay. + // We need to decrease extra video delay, if we have added extra delay + // earlier, or add extra audio delay. + if (_channelDelay.extraVideoDelayMS > 0) + { + // We have extra delay added to ViE. + // Reduce this delay before adding delay to VE. + + // This is the desired delay, we can't reduce more than this. + videoDelayMS = totalVideoDelayTargetMS; + + // Check we don't reduce the delay too much + if (videoDelayMS < _channelDelay.lastVideoDelayMS + - kMaxVideoDiffMS) + { + // Too large step... + videoDelayMS = _channelDelay.lastVideoDelayMS + - kMaxVideoDiffMS; + _channelDelay.extraVideoDelayMS = videoDelayMS + - totalVideoDelayTargetMS; + } else + { + _channelDelay.extraVideoDelayMS = 0; + } + _channelDelay.lastVideoDelayMS = videoDelayMS; + _channelDelay.lastSyncDelay = -1; + _channelDelay.extraAudioDelayMS = 0; + } else + { + // We have no extra video delay to remove. + // Increase the audio delay + if (_channelDelay.lastSyncDelay >= 0) + { + // We have increased the audio delay earlier, + // increase it even more. + int audioDiffMS = currentDiffMS / 2; + if (audioDiffMS > kMaxAudioDiffMS) + { + // We only allow a maximum change of KMaxAudioDiffMS for audio + // due to NetEQ maximum changes. + audioDiffMS = kMaxAudioDiffMS; + } + // Increase the audio delay + _channelDelay.extraAudioDelayMS += audioDiffMS; + + // Don't set a too high delay. + if (_channelDelay.extraAudioDelayMS > kMaxDelay) + { + _channelDelay.extraAudioDelayMS = kMaxDelay; + } + + // Don't add any extra video delay. + videoDelayMS = totalVideoDelayTargetMS; + _channelDelay.extraVideoDelayMS = 0; + _channelDelay.lastVideoDelayMS = videoDelayMS; + + _channelDelay.lastSyncDelay = 1; + } else // lastSyncDelay < 0 + { + // First time after a delay change, don't add any extra delay. + // This is to not toggle back and forth too much. + _channelDelay.extraAudioDelayMS = 0; + // Set minimum video delay + videoDelayMS = totalVideoDelayTargetMS; + _channelDelay.extraVideoDelayMS = 0; + _channelDelay.lastVideoDelayMS = videoDelayMS; + _channelDelay.lastSyncDelay = 0; + } + } + } else // if (currentDiffMS > 0) + { + // The minimum video delay is lower than the current audio delay. + // We need to decrease possible extra audio delay, or + // add extra video delay. + + if (_channelDelay.extraAudioDelayMS > 0) + { + // We have extra delay in VoiceEngine + // Start with decreasing the voice delay + int audioDiffMS = currentDiffMS / 2; // This is a negative value + if (audioDiffMS < -1 * kMaxAudioDiffMS) + { + // Don't change the delay too much at once. + audioDiffMS = -1 * kMaxAudioDiffMS; + } + _channelDelay.extraAudioDelayMS += audioDiffMS; // Add the negative change... + + if (_channelDelay.extraAudioDelayMS < 0) + { + // Negative values not allowed + _channelDelay.extraAudioDelayMS = 0; + _channelDelay.lastSyncDelay = 0; + } else + { + // There is more audio delay to use for the next round. + _channelDelay.lastSyncDelay = 1; + } + + // Keep the video delay at the minimum values. + videoDelayMS = totalVideoDelayTargetMS; + _channelDelay.extraVideoDelayMS = 0; + _channelDelay.lastVideoDelayMS = videoDelayMS; + } else + { + // We have no extra delay in VoiceEngine + // Increase the video delay + _channelDelay.extraAudioDelayMS = 0; + + // Make the diff positive + int videoDiffMS = -1 * currentDiffMS; + + // This is the desired delay we want + videoDelayMS = totalVideoDelayTargetMS + videoDiffMS; + if (videoDelayMS > _channelDelay.lastVideoDelayMS) + { + if (videoDelayMS > _channelDelay.lastVideoDelayMS + + kMaxVideoDiffMS) + { + // Don't increase the delay too much at once + videoDelayMS = _channelDelay.lastVideoDelayMS + + kMaxVideoDiffMS; + } + // Verify we don't go above the maximum allowed delay + if (videoDelayMS > kMaxDelay) + { + videoDelayMS = kMaxDelay; + } + } else + { + if (videoDelayMS < _channelDelay.lastVideoDelayMS + - kMaxVideoDiffMS) + { + // Don't decrease the delay too much at once + videoDelayMS = _channelDelay.lastVideoDelayMS + - kMaxVideoDiffMS; + } + // Verify we don't go below the minimum delay + if (videoDelayMS < totalVideoDelayTargetMS) + { + videoDelayMS = totalVideoDelayTargetMS; + } + } + // Store the values + _channelDelay.extraVideoDelayMS = videoDelayMS + - totalVideoDelayTargetMS; + _channelDelay.lastVideoDelayMS = videoDelayMS; + _channelDelay.lastSyncDelay = -1; + } + } + } + + WEBRTC_TRACE( + webrtc::kTraceInfo, + webrtc::kTraceVideo, + _id, + "Sync video delay %d ms for video channel and audio delay %d for audio channel %d", + videoDelayMS, _channelDelay.extraAudioDelayMS, + _voiceChannelId); + + // Set the extra audio delay + if (_voiceSyncInterface->SetMinimumPlayoutDelay(_voiceChannelId, + _channelDelay.extraAudioDelayMS) == -1) + { + WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo, _id, + "Error setting voice delay"); + } + + // sanity + // negative not valid + if (videoDelayMS < 0) + { + videoDelayMS = 0; + } + totalVideoDelayTargetMS = (totalVideoDelayTargetMS > videoDelayMS) ? + totalVideoDelayTargetMS : videoDelayMS; + _vcm.SetMinimumPlayoutDelay(totalVideoDelayTargetMS); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _id, + "New Video delay target is: %d", totalVideoDelayTargetMS); + } + return 0; +} +} // namespace webrtc diff --git a/video_engine/main/source/vie_sync_module.h b/video_engine/main/source/vie_sync_module.h new file mode 100644 index 0000000000..fc92f862cd --- /dev/null +++ b/video_engine/main/source/vie_sync_module.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_sync_module.h + * Responsible for doing Audio/Video sync + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_SYNC_MODULE_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_SYNC_MODULE_H_ + +#include "module.h" +#include "tick_util.h" + +namespace webrtc +{ +class CriticalSectionWrapper; +class RtpRtcp; +class VideoCodingModule; +class VoEVideoSync; + + +class ViESyncModule : public Module +{ +public: + enum { kSyncInterval = 1000}; + enum { kMaxVideoDiffMS = 80 }; // Video sync + enum { kMaxAudioDiffMS = 80 }; // Video sync + enum { kMaxDelay = 1500 }; // Video sync + + ViESyncModule(int id, VideoCodingModule& vcm, + RtpRtcp& rtcpModule); + ~ViESyncModule(); + int SetVoiceChannel(int voiceChannelId, VoEVideoSync* voiceSyncInterface); + int VoiceChannel(); + void SetNetworkDelay(int networkDelay); + + // Implements Module + virtual WebRtc_Word32 Version(WebRtc_Word8* version, + WebRtc_UWord32& remainingBufferInBytes, + WebRtc_UWord32& position) const; + + virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id); + virtual WebRtc_Word32 TimeUntilNextProcess(); + virtual WebRtc_Word32 Process(); + +private: + // Critical sections + CriticalSectionWrapper& _dataCritsect; + int _id; + VideoCodingModule& _vcm; + RtpRtcp& _rtcpModule; + int _voiceChannelId; + VoEVideoSync* _voiceSyncInterface; + TickTime _lastSyncTime; + + struct ViESyncDelay + { + ViESyncDelay() + { + extraVideoDelayMS = 0; + lastVideoDelayMS = 0; + extraAudioDelayMS = 0; + lastSyncDelay = 0; + networkDelay = 120; + } + int extraVideoDelayMS; + int lastVideoDelayMS; + int extraAudioDelayMS; //audioDelayMS; + int lastSyncDelay; + int networkDelay; + }; + ViESyncDelay _channelDelay; + +}; +} // namespace webrtc +#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_SYNC_MODULE_H_ diff --git a/video_engine/main/test/AndroidTest/.classpath b/video_engine/main/test/AndroidTest/.classpath new file mode 100644 index 0000000000..f2adf55d20 --- /dev/null +++ b/video_engine/main/test/AndroidTest/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/video_engine/main/test/AndroidTest/.project b/video_engine/main/test/AndroidTest/.project new file mode 100644 index 0000000000..6765ec26c5 --- /dev/null +++ b/video_engine/main/test/AndroidTest/.project @@ -0,0 +1,33 @@ + + + ViEAndroidDemo + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/video_engine/main/test/AndroidTest/AndroidManifest.xml b/video_engine/main/test/AndroidTest/AndroidManifest.xml new file mode 100644 index 0000000000..670f2a3ccb --- /dev/null +++ b/video_engine/main/test/AndroidTest/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/video_engine/main/test/AndroidTest/default.properties b/video_engine/main/test/AndroidTest/default.properties new file mode 100644 index 0000000000..c206f58583 --- /dev/null +++ b/video_engine/main/test/AndroidTest/default.properties @@ -0,0 +1,13 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Indicates whether an apk should be generated for each density. +split.density=false +# Project target. +target=android-9 diff --git a/video_engine/main/test/AndroidTest/gen/org/webrtc/androidapp/R.java b/video_engine/main/test/AndroidTest/gen/org/webrtc/androidapp/R.java new file mode 100644 index 0000000000..c35047b661 --- /dev/null +++ b/video_engine/main/test/AndroidTest/gen/org/webrtc/androidapp/R.java @@ -0,0 +1,68 @@ +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package org.webrtc.videoengineapp; + +public final class R { + public static final class array { + public static final int codecSize=0x7f040001; + public static final int codectype=0x7f040000; + public static final int voiceCodecType=0x7f040002; + } + public static final class attr { + } + public static final class drawable { + public static final int bar=0x7f020000; + public static final int bg=0x7f020001; + public static final int logo=0x7f020002; + public static final int robot=0x7f020003; + public static final int video=0x7f020004; + } + public static final class id { + public static final int LinearLayout01=0x7f060010; + public static final int LinearLayout02=0x7f060006; + public static final int TextView01=0x7f060005; + public static final int TextView02=0x7f06000b; + public static final int TextView03=0x7f060004; + public static final int btStartBoth=0x7f060013; + public static final int btStartListen=0x7f060011; + public static final int btStartSend=0x7f060012; + public static final int cbLoopback=0x7f06000e; + public static final int cbVoice=0x7f06000d; + public static final int etRemoteIp=0x7f06000c; + public static final int ivPreview=0x7f060014; + public static final int ivTopBar=0x7f060002; + public static final int rlSurfaces=0x7f060000; + public static final int spCodecSize=0x7f06000a; + public static final int spCodecType=0x7f060007; + public static final int spVoiceCodecType=0x7f060008; + public static final int svLocal=0x7f060001; + public static final int tvCodecSize=0x7f060009; + public static final int tvLocalIp=0x7f06000f; + public static final int tvTitle=0x7f060003; + } + public static final class layout { + public static final int both=0x7f030000; + public static final int main=0x7f030001; + public static final int send=0x7f030002; + } + public static final class string { + public static final int app_name=0x7f050001; + public static final int codecSize=0x7f050007; + public static final int codecType=0x7f050006; + public static final int codectype_prompt=0x7f050004; + public static final int demoTitle=0x7f050005; + public static final int enableVoice=0x7f05000d; + public static final int error=0x7f050002; + public static final int errorCamera=0x7f050003; + public static final int loopback=0x7f050009; + public static final int remoteIp=0x7f050008; + public static final int startBoth=0x7f05000c; + public static final int startListen=0x7f05000a; + public static final int startSend=0x7f05000b; + } +} diff --git a/video_engine/main/test/AndroidTest/jni/org_webrtc_videoengineapp_vie_android_java_api.h b/video_engine/main/test/AndroidTest/jni/org_webrtc_videoengineapp_vie_android_java_api.h new file mode 100644 index 0000000000..e74b7a7846 --- /dev/null +++ b/video_engine/main/test/AndroidTest/jni/org_webrtc_videoengineapp_vie_android_java_api.h @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_webrtc_videoengineapp_ViEAndroidJavaAPI */ + +#ifndef _Included_org_webrtc_videoengineapp_ViEAndroidJavaAPI +#define _Included_org_webrtc_videoengineapp_ViEAndroidJavaAPI +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: NativeInit + * Signature: (Landroid/content/Context;)Z + */ +JNIEXPORT jboolean JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_NativeInit + (JNIEnv *, jobject, jobject); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: GetVideoEngine + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetVideoEngine + (JNIEnv *, jobject); + + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: Init + * Signature: (IIIZ)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1Init + (JNIEnv *, jobject, jint, jint, jint, jboolean); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: Terminate + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1Terminate + (JNIEnv *, jobject); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StartSend + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StartSend + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StopRender + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StopRender + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StopSend + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StopSend + (JNIEnv *, jobject,jint); + + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StartReceive + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StartReceive + (JNIEnv *, jobject,jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StopReceive + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StopReceive + (JNIEnv *, jobject,jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: CreateChannel + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1CreateChannel + (JNIEnv *, jobject,jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetLocalReceiver + * Signature: (II)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetLocalReceiver + (JNIEnv *, jobject, jint, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetSendDestination + * Signature: (II[B)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetSendDestination + (JNIEnv *, jobject, jint, jint, jbyteArray); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetReceiveCodec + * Signature: (IIIIIIZ)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetReceiveCodec + (JNIEnv *, jobject, jint, jint, jint, jint, jint, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetSendCodec + * Signature: (IIIIIIZ)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetSendCodec + (JNIEnv *, jobject, jint, jint, jint, jint, jint, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: AddRemoteRenderer + * Signature: (ILandroid/view/SurfaceView;)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1AddRemoteRenderer + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: RemoveRemoteRenderer + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1RemoveRemoteRenderer + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StartRender + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StartRender + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StartCamera + * Signature: (II)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StartCamera + (JNIEnv *, jobject,jint channel,jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StopCamera + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StopCamera + (JNIEnv *, jobject,jint); + + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: GetCameraOrientation + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1GetCameraOrientation + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetRotation + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetRotation + (JNIEnv *, jobject, jint, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: EnableNACK + * Signature: (IZ)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1EnableNACK + (JNIEnv *, jobject, jint, jboolean); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: EnablePLI + * Signature: (IZ)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1EnablePLI + (JNIEnv *, jobject, jint, jboolean); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StartSendNative + * Signature: (III[BIIIIIILandroid/view/SurfaceView;III)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StartSendNative + (JNIEnv *, jobject, jint, jint, jint, jbyteArray, jint, jint, jint, jint, jint, jint, jobject, jint, jint, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StartListenNative + * Signature: (III[BIIIIIIILandroid/view/SurfaceView;)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StartListenNative + (JNIEnv *, jobject, jint, jint, jint, jbyteArray, jint, jint, jint, jint, jint, jint, jint, jobject); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StopAllNative + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StopAllNative + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetCallback + * Signature: (ILorg/webrtc/videoengineapp/IViEAndroidCallback;)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetCallback + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_Create + * Signature: (Landroid/app/Activity;)Z + */ +JNIEXPORT jboolean JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1Create + (JNIEnv *, jobject, jobject); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_Delete + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1Delete + (JNIEnv *, jobject); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_Init + * Signature: (IIIZZ)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1Init + (JNIEnv *, jobject, jint, jint, jint, jboolean, jboolean); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_Terminate + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1Terminate + (JNIEnv *, jobject); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_CreateChannel + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1CreateChannel + (JNIEnv *, jobject); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_DeleteChannel + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1DeleteChannel + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_SetLocalReceiver + * Signature: (II)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetLocalReceiver + (JNIEnv *, jobject, jint, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_SetSendDestination + * Signature: (IILjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetSendDestination + (JNIEnv *, jobject, jint, jint, jstring); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_StartListen + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StartListen + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_StartPlayout + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StartPlayout + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_StartSend + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StartSend + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_StopListen + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StopListen + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_StopPlayout + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StopPlayout + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_StopSend + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StopSend + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_SetSpeakerVolume + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetSpeakerVolume + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_SetLoudspeakerStatus + * Signature: (Z)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetLoudspeakerStatus + (JNIEnv *, jobject, jboolean); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_StartPlayingFileLocally + * Signature: (ILjava/lang/String;Z)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StartPlayingFileLocally + (JNIEnv *, jobject, jint, jstring, jboolean); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_StopPlayingFileLocally + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StopPlayingFileLocally + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_StartPlayingFileAsMicrophone + * Signature: (ILjava/lang/String;Z)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StartPlayingFileAsMicrophone + (JNIEnv *, jobject, jint, jstring, jboolean); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_StopPlayingFileAsMicrophone + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StopPlayingFileAsMicrophone + (JNIEnv *, jobject, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_NumOfCodecs + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1NumOfCodecs + (JNIEnv *, jobject); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_SetSendCodec + * Signature: (II)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetSendCodec + (JNIEnv *, jobject, jint, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_SetECStatus + * Signature: (ZI)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetECStatus + (JNIEnv *, jobject, jboolean, jint, jint, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_SetNSStatus + * Signature: (ZI)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetNSStatus + (JNIEnv *, jobject, jboolean, jint); + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: VE_SetAGCStatus + * Signature: (ZI)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetAGCStatus + (JNIEnv *, jobject, jboolean, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/video_engine/main/test/AndroidTest/jni/vie_android_java_api.cc b/video_engine/main/test/AndroidTest/jni/vie_android_java_api.cc new file mode 100644 index 0000000000..b80f9d44cd --- /dev/null +++ b/video_engine/main/test/AndroidTest/jni/vie_android_java_api.cc @@ -0,0 +1,1751 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include +#include + +#include "org_webrtc_videoengineapp_vie_android_java_api.h" + +#include "voe_base.h" +#include "voe_codec.h" +#include "voe_file.h" +#include "voe_network.h" +#include "voe_audio_processing.h" +#include "voe_volume_control.h" +#include "voe_hardware.h" + +#include "vie_base.h" +#include "vie_codec.h" +#include "vie_capture.h" +#include "vie_network.h" +#include "vie_render.h" +#include "vie_rtp_rtcp.h" + +#include "common_types.h" + +#define WEBRTC_LOG_TAG "*WEBRTCN*" +#define VALIDATE_BASE_POINTER \ + if (!veData.base) \ + { \ + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, "Base pointer doesn't exist"); \ + return -1; \ + } +#define VALIDATE_CODEC_POINTER \ + if (!veData.codec) \ + { \ + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, "Codec pointer doesn't exist"); \ + return -1; \ + } +#define VALIDATE_FILE_POINTER \ + if (!veData.file) \ + { \ + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, "File pointer doesn't exist"); \ + return -1; \ + } +#define VALIDATE_APM_POINTER \ + if (!veData.codec) \ + { \ + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, "Apm pointer doesn't exist"); \ + return -1; \ + } +#define VALIDATE_HARDWARE_POINTER \ + if (!veData.hardware) \ + { \ + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, "Hardware pointer doesn't exist"); \ + return -1; \ + } +#define VALIDATE_VOLUME_POINTER \ + if (!veData.volume) \ + { \ + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, "Volume pointer doesn't exist"); \ + return -1; \ + } + +using namespace webrtc; + +//Forward declaration. +class VideoCallbackAndroid; + +// VoiceEngine data struct +typedef struct +{ + // VoiceEngine + VoiceEngine* ve; + // Sub-APIs + VoEBase* base; + VoECodec* codec; + VoEFile* file; + VoENetwork* netw; + VoEAudioProcessing* apm; + VoEVolumeControl* volume; + VoEHardware* hardware; + JavaVM* jvm; +} VoiceEngineData; + +class AndroidVideoRenderCallback; +// VideoEngine data struct +typedef struct +{ + VideoEngine* vie; + ViEBase* base; + ViECodec* codec; + ViENetwork* netw; + ViERTP_RTCP* rtp; + ViERender* render; + ViECapture* capture; + VideoCallbackAndroid* callback; + +} VideoEngineData; + +// Global variables +JavaVM* webrtcGlobalVM; + +// Global variables visible in this file +static VoiceEngineData veData; +static VideoEngineData vieData; + +// "Local" functions (i.e. not Java accessible) +#define WEBRTC_TRACE_MAX_MESSAGE_SIZE 1024 +static bool VE_GetSubApis(); +static bool VE_ReleaseSubApis(); + +#define CHECK_API_RETURN(ret) \ + if (ret!=0) \ + { \ + __android_log_print(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, "Return error %d",ret); \ + break; \ + } + +class VideoCallbackAndroid: public ViEDecoderObserver, + public ViEEncoderObserver +{ + + // Implements ViEDecoderObserver + virtual void IncomingRate(const int videoChannel, + const unsigned int framerate, + const unsigned int bitrate) + { + //Let's print out the network statistics from this call back as well + unsigned short fraction_lost; + unsigned int dummy; + int intdummy; + _vieData.rtp->GetReceivedRTCPStatistics(videoChannel, fraction_lost, + dummy, dummy, dummy, intdummy); + unsigned short packetLossRate = 0; + if (fraction_lost > 0) + { + // Change from frac to % + packetLossRate = (fraction_lost * 100) >> 8; + } + + JNIEnv* threadEnv = NULL; + int ret = webrtcGlobalVM->AttachCurrentThread(&threadEnv, NULL); + // Get the JNI env for this thread + if ((ret < 0) || !threadEnv) + { + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "Could not attach thread to JVM (%d, %p)", ret, + threadEnv); + return; + } + threadEnv->CallIntMethod(_callbackObj, _callbackId, framerate, bitrate, + packetLossRate, _frameRateO, _bitRateO); + webrtcGlobalVM->DetachCurrentThread(); + } + ; + + virtual void IncomingCodecChanged(const int videoChannel, + const webrtc::VideoCodec& videoCodec) + { + } + ; + + virtual void RequestNewKeyFrame(const int videoChannel) + { + } + ; + + virtual void OutgoingRate(const int videoChannel, + const unsigned int framerate, + const unsigned int bitrate) + { + _frameRateO = framerate; + _bitRateO = bitrate; + //__android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "SendRate frameRate %d bitrate %d\n",frameRate,bitrate); + } + ; + +public: + VideoEngineData& _vieData; + JNIEnv * _env; + jobject _callbackObj; + jclass _callbackCls; + jmethodID _callbackId; + int _frameRateO, _bitRateO; + VideoCallbackAndroid(VideoEngineData& vieData, JNIEnv * env, + jobject callback) : + _vieData(vieData), _env(env), _callbackObj(callback), _frameRateO(0), + _bitRateO(0) + { + _callbackCls = _env->GetObjectClass(_callbackObj); + _callbackId + = _env->GetMethodID(_callbackCls, "UpdateStats", "(IIIII)I"); + if (_callbackId == NULL) + { + __android_log_print(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Failed to get jid"); + } + _callbackObj = _env->NewGlobalRef(_callbackObj); + } +}; + +////////////////////////////////////////////////////////////////// +// General functions +////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////// +// JNI_OnLoad +jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) +{ + webrtcGlobalVM = vm; + if (!webrtcGlobalVM) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "JNI_OnLoad did not receive a valid VM pointer"); + return -1; + } + + // Get JNI + JNIEnv* env; + if (JNI_OK != vm->GetEnv(reinterpret_cast (&env), JNI_VERSION_1_4)) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "JNI_OnLoad could not get JNI env"); + return -1; + } + + // Init VoiceEngine data + memset(&veData, 0, sizeof(veData)); + // Store the JVM + veData.jvm = vm; + + // Init VideoEngineData data + memset(&vieData, 0, sizeof(vieData)); + + return JNI_VERSION_1_4; +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: NativeInit + * Signature: (Landroid/content/Context;)Z + */ +JNIEXPORT jboolean JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_NativeInit( + JNIEnv * env, + jobject, + jobject context) +{ + + return true; +} + +////////////////////////////////////////////////////////////////// +// VideoEngine API wrapper functions +////////////////////////////////////////////////////////////////// +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: GetVideoEngine + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetVideoEngine( + JNIEnv *, + jobject context) +{ + + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "GetVideoEngine"); + + VideoEngine::SetAndroidObjects(webrtcGlobalVM, context); + + // Check if already got + if (vieData.vie) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "ViE already got"); + return -1; + } + + // Create + vieData.vie = VideoEngine::Create(); + if (!vieData.vie) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, "Get ViE failed"); + return -1; + } + vieData.base = ViEBase::GetInterface(vieData.vie); + if (!vieData.base) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get base sub-API failed"); + return -1; + } + + vieData.codec = ViECodec::GetInterface(vieData.vie); + if (!vieData.codec) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get codec sub-API failed"); + return -1; + } + + vieData.netw = ViENetwork::GetInterface(vieData.vie); + if (!vieData.netw) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get network sub-API failed"); + return -1; + } + + vieData.rtp = ViERTP_RTCP::GetInterface(vieData.vie); + if (!vieData.rtp) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get RTP sub-API failed"); + return -1; + } + + vieData.render = ViERender::GetInterface(vieData.vie); + if (!vieData.render) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get Render sub-API failed"); + return -1; + } + vieData.capture = ViECapture::GetInterface(vieData.vie); + if (!vieData.capture) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get Capture sub-API failed"); + return -1; + } + + return 0; +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: Init + * Signature: (IIIZ)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1Init( + JNIEnv *, + jobject, + jboolean enableTrace) +{ + if (vieData.vie) + { + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "Init"); + + int ret = vieData.base->Init(); + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "Init return %d", ret); + if (enableTrace) + { + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "SetTraceFile"); + if (0 != vieData.vie->SetTraceFile(("/sdcard/trace.txt"), false)) + { + __android_log_print(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Video Engine could not enable trace"); + } + + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "SetTraceFilter"); + if (0 != vieData.vie->SetTraceFilter(webrtc::kTraceDefault)) + { + __android_log_write(ANDROID_LOG_WARN, WEBRTC_LOG_TAG, + "Could not set trace filter"); + } + } + else + { + if (0 != vieData.vie->SetTraceFilter(webrtc::kTraceNone)) + { + __android_log_write(ANDROID_LOG_WARN, WEBRTC_LOG_TAG, + "Could not set trace filter"); + } + } + if (veData.ve) // VoiceEngine is enabled + { + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "SetVoiceEngine"); + if (0 != vieData.base->SetVoiceEngine(veData.ve)) + { + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "SetVoiceEngine failed"); + } + } + return ret; + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: Terminate + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1Terminate( + JNIEnv *, + jobject) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "Terminate"); + + if (vieData.vie) + { + if (!vieData.rtp || vieData.rtp->Release() != 0) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Failed to release RTP sub-API"); + + } + if (!vieData.netw || vieData.netw->Release() != 0) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Failed to release Network sub-API"); + + } + if (!vieData.codec || vieData.codec->Release() != 0) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Failed to release Codec sub-API"); + + } + if (!vieData.render || vieData.render->Release()) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Failed to release Render sub-API"); + } + if (!vieData.capture || vieData.capture->Release()) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Failed to release Capture sub-API"); + } + + if (!vieData.base || vieData.base->Release() != 0) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Failed to release Base sub-API"); + } + // Delete Vie + if (!VideoEngine::Delete(vieData.vie)) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Failed to delete ViE "); + return -1; + } + memset(&vieData, 0, sizeof(vieData)); + VideoEngine::SetAndroidObjects(NULL, NULL); + return 0; + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StartSend + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StartSend( + JNIEnv *, + jobject, + jint channel) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "StartSend"); + + if (vieData.base) + { + int ret = vieData.base->StartSend(channel); + return ret; + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StopRender + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StopRender( + JNIEnv *, + jobject, + jint channel) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "StopRender"); + + if (vieData.render) + { + return vieData.render->StopRender(channel); + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: Stop + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StopSend( + JNIEnv *, + jobject, + jint channel) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "StopSend"); + + if (vieData.base) + { + return vieData.base->StopSend(channel); + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StartReceive + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StartReceive( + JNIEnv *, + jobject, + jint channel) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "StartReceive"); + + if (vieData.base) + { + return vieData.base->StartReceive(channel); + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StopReceive + * Signature: ()I + */ + +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StopReceive( + JNIEnv *, + jobject, + jint channel) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "StopReceive"); + if (vieData.base) + { + return vieData.base->StopReceive(channel); + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: CreateChannel + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1CreateChannel( + JNIEnv *, + jobject, + jint voiceChannel) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "CreateChannel"); + + if (vieData.vie) + { + int channel = 0; + if (vieData.base->CreateChannel(channel) != 0) + { + return -1; + } + if (voiceChannel >= 0) + { + vieData.base->ConnectAudioChannel(channel, voiceChannel); + } + + return channel; + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetLocalReceiver + * Signature: (II)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetLocalReceiver( + JNIEnv *, + jobject, + jint channel, + jint port) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "SetLocalReceiver"); + + if (vieData.vie) + { + int ret = vieData.netw->SetLocalReceiver(channel, port); + return ret; + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetSendDestination + * Signature: (II[B)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetSendDestination( + JNIEnv * env, + jobject, + jint channel, + jint port, + jbyteArray ipadr) +{ + + if (NULL == vieData.vie) + return -1; + + char ip[64]; + jsize len = env->GetArrayLength(ipadr); + if ((len >= 64) || (len == 0)) + return -1; + env->GetByteArrayRegion(ipadr, 0, len, (jbyte*) ip); + ip[len] = '\0'; + + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "SetSendDestination: channel=%d, port=%d, ip=%s\n", + channel, port, ip); + + int ret = vieData.netw->SetSendDestination(channel, ip, port); + return ret; +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetReceiveCodec + * Signature: (IIIIII)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetReceiveCodec( + JNIEnv *, + jobject, + jint channel, + jint codecNum, + jint intbitRate, + jint width, + jint height, + jint frameRate) +{ + if (NULL == vieData.codec) + return -1; + + //Create codec + webrtc::VideoCodec codec; + vieData.codec->GetCodec(codecNum, codec); + + __android_log_print( + ANDROID_LOG_DEBUG, + WEBRTC_LOG_TAG, + "SetReceiveCodec %s, pltype=%d, bitRate=%d, maxBitRate=%d," + " width=%d, height=%d, frameRate=%d, codecSpecific=%d \n", + codec.plName, codec.plType, codec.startBitrate, + codec.maxBitrate, codec.width, codec.height, + codec.maxFramerate, codec.codecSpecific); + int ret = vieData.codec->SetReceiveCodec(channel, codec); + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "SetReceiveCodec return %d", ret); + return ret; +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetSendCodec + * Signature: (IIIIII)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetSendCodec( + JNIEnv *, + jobject, + jint channel, + jint codecNum, + jint intbitRate, + jint width, + jint height, + jint frameRate) +{ + if (NULL == vieData.codec) + return -1; + + //Create codec + webrtc::VideoCodec codec; + vieData.codec->GetCodec(codecNum, codec); + codec.startBitrate = intbitRate; + codec.maxBitrate = 600; + codec.width = width; + codec.height = height; + codec.maxFramerate = frameRate; + + for (int i = 0; i < vieData.codec->NumberOfCodecs(); ++i) + { + webrtc::VideoCodec codecToList; + vieData.codec->GetCodec(i, codecToList); + __android_log_print( + ANDROID_LOG_DEBUG, + WEBRTC_LOG_TAG, + "Codec list %s, pltype=%d, bitRate=%d, maxBitRate=%d," + " width=%d, height=%d, frameRate=%d\n", + codecToList.plName, codecToList.plType, + codecToList.startBitrate, codecToList.maxBitrate, + codecToList.width, codecToList.height, + codecToList.maxFramerate); + } + __android_log_print( + ANDROID_LOG_DEBUG, + WEBRTC_LOG_TAG, + "SetSendCodec %s, pltype=%d, bitRate=%d, maxBitRate=%d, " + "width=%d, height=%d, frameRate=%d\n", + codec.plName, codec.plType, codec.startBitrate, + codec.maxBitrate, codec.width, codec.height, + codec.maxFramerate); + + return vieData.codec->SetSendCodec(channel, codec); +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: AddRemoteRenderer + * Signature: (ILandroid/view/SurfaceView;)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1AddRemoteRenderer( + JNIEnv *, + jobject, + jint channel, + jobject glSurface) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "AddRemoteRenderer"); + if (vieData.vie) + { + return vieData.render->AddRenderer(channel, glSurface, 0, 0, 0, 1, 1); + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: RemoveRemoteRenderer + * Signature: (I)I + */ +JNIEXPORT jint +JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1RemoveRemoteRenderer( + JNIEnv *, + jobject, + jint channel) +{ + if (vieData.vie) + { + return vieData.render->RemoveRenderer(channel); + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StartRender + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StartRender( + JNIEnv *, + jobject, + jint channel) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "StartRender"); + + if (vieData.render) + { + return vieData.render->StartRender(channel); + } + else + { + return -1; + } +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StarteCamera + * Signature: (II)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StartCamera( + JNIEnv * env, + jobject, + jint channel, + jint cameraNum) +{ + if (NULL == vieData.vie) + return -1; + + int i = 0; + char deviceName[64]; + char deviceUniqueName[64]; + int re; + do + { + re = vieData.capture->GetCaptureDevice(i, deviceName, + sizeof(deviceName), + deviceUniqueName, + sizeof(deviceUniqueName)); + __android_log_print( + ANDROID_LOG_DEBUG, + WEBRTC_LOG_TAG, + "GetCaptureDevice ret %d devicenum %d deviceUniqueName %s", + re, i, deviceUniqueName); + i++; + } while (re == 0); + + int ret; + int cameraId; + vieData.capture->GetCaptureDevice(cameraNum, deviceName, + sizeof(deviceName), deviceUniqueName, + sizeof(deviceUniqueName)); + vieData.capture->AllocateCaptureDevice(deviceUniqueName, + sizeof(deviceUniqueName), cameraId); + + if (cameraId >= 0) + { //Connect the + ret = vieData.capture->ConnectCaptureDevice(cameraId, channel); + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "ConnectCaptureDevice ret %d ", ret); + + ret = vieData.capture->StartCapture(cameraId); + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "StartCapture ret %d ", ret); + + } + + return cameraId; +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: StopCamera + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1StopCamera( + JNIEnv *, + jobject, + jint cameraId) +{ + if (NULL == vieData.capture) + return -1; + + int ret = vieData.capture->StopCapture(cameraId); + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "StopCapture ret %d ", ret); + ret = vieData.capture->ReleaseCaptureDevice(cameraId); + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "ReleaseCaptureDevice ret %d ", ret); + + return ret; +} +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: GetCameraOrientation + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1GetCameraOrientation( + JNIEnv *, + jobject, + jint cameraNum) +{ + char deviceName[64]; + char deviceUniqueName[64]; + int ret; + + ret = vieData.capture->GetCaptureDevice(cameraNum, deviceName, + sizeof(deviceName), + deviceUniqueName, + sizeof(deviceUniqueName)); + if (ret != 0) + { + return -1; + } + + RotateCapturedFrame orientation; + ret = vieData.capture->GetOrientation(deviceUniqueName, orientation); + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "GetOrientation ret %d orientation %d", ret, + orientation); + + return (jint) orientation; + +} +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetRotation + * Signature: (II)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetRotation( + JNIEnv *, + jobject, + jint captureId, + jint degrees) +{ + + if (NULL == vieData.capture) + return -1; + RotateCapturedFrame rotation = RotateCapturedFrame_0; + if (degrees == 90) + rotation = RotateCapturedFrame_90; + else if (degrees == 180) + rotation = RotateCapturedFrame_180; + else if (degrees == 270) + rotation = RotateCapturedFrame_270; + + int ret = vieData.capture->SetRotateCapturedFrames(captureId, rotation); + return ret; +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: EnableNACK + * Signature: (IZ)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1EnableNACK( + JNIEnv *, + jobject, + jint channel, + jboolean enable) +{ + if (NULL == vieData.rtp) + return -1; + + if (enable) + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "EnableNACK enable"); + else + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "EnableNACK disable"); + + int ret = vieData.rtp->SetNACKStatus(channel, enable); + return ret; +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: EnablePLI + * Signature: (IZ)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1EnablePLI( + JNIEnv *, + jobject, + jint channel, + jboolean enable) +{ + if (NULL == vieData.rtp) + return -1; + + if (enable) + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "EnablePLI enable"); + else + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "EnablePLI disable"); + + int ret = vieData.rtp->SetKeyFrameRequestMethod(channel, + kViEKeyFrameRequestPliRtcp); + return ret; +} + +/* + * Class: org_webrtc_videoengineapp_ViEAndroidJavaAPI + * Method: SetCallback + * Signature: (ILorg/webrtc/videoengineapp/IViEAndroidCallback;)I + */ +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_1SetCallback( + JNIEnv * env, + jobject, + jint channel, + jobject callback) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "SetCallback"); + + if (NULL == vieData.codec) + return -1; + if (vieData.callback == NULL) + { + vieData.callback = new VideoCallbackAndroid(vieData, env, callback); + } + else if (vieData.codec) + { + vieData.codec->DeregisterDecoderObserver(channel); // Wrong channel? + vieData.codec->DeregisterEncoderObserver(channel); + } + + vieData.codec->RegisterDecoderObserver(channel, *vieData.callback); + vieData.codec->RegisterEncoderObserver(channel, *vieData.callback); + + return 0; +} +////////////////////////////////////////////////////////////////// +// VoiceEngine API wrapper functions +////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////// +// Create VoiceEngine instance +// +JNIEXPORT jboolean JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1Create( + JNIEnv *env, + jobject, + jobject context) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "Create"); + + // Check if already created + if (veData.ve) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "VoE already created"); + return false; + } + + // Init Android Object + VoiceEngine::SetAndroidObjects(veData.jvm, env, context); + // Create + veData.ve = VoiceEngine::Create(); + if (!veData.ve) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Create VoE failed"); + return false; + } + + // Get sub-APIs + if (!VE_GetSubApis()) + { + // If not OK, release all sub-APIs and delete VoE + VE_ReleaseSubApis(); + if (!VoiceEngine::Delete(veData.ve)) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Delete VoE failed"); + } + return false; + } + + return true; +} + +///////////////////////////////////////////// +// Delete VoiceEngine instance +// +JNIEXPORT jboolean JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1Delete( + JNIEnv *, + jobject) +{ + // Check if exists + if (!veData.ve) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "VoE does not exist"); + return false; + } + + // Release sub-APIs + VE_ReleaseSubApis(); + + // Delete + if (!VoiceEngine::Delete(veData.ve)) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Delete VoE failed"); + return false; + } + + veData.ve = NULL; + + // Clear instance independent Java objects + VoiceEngine::SetAndroidObjects(NULL, NULL, NULL); + + return true; +} + +///////////////////////////////////////////// +// [Base] Initialize VoiceEngine +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1Init( + JNIEnv *, + jobject, + jboolean enableTrace, + jboolean useExtTrans) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "VE_Init"); + + VALIDATE_BASE_POINTER; + + if (useExtTrans) + { + // Not implemented + return -1; + } + + return veData.base->Init(); +} + +///////////////////////////////////////////// +// [Base] Terminate VoiceEngine +// +JNIEXPORT jint +JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1Terminate( + JNIEnv *, + jobject) +{ + VALIDATE_BASE_POINTER; + + jint retVal = veData.base->Terminate(); + return retVal; +} + +///////////////////////////////////////////// +// [Base] Create channel +// +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1CreateChannel( + JNIEnv *, + jobject) +{ + VALIDATE_BASE_POINTER; + + webrtc::CodecInst voiceCodec; + int numOfVeCodecs = veData.codec->NumOfCodecs(); + + //enum all the supported codec + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "Supported Voice Codec:\n"); + for (int i = 0; i < numOfVeCodecs; ++i) + { + if (veData.codec->GetCodec(i, voiceCodec) != -1) + { + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "num: %d name: %s\n", i, voiceCodec.plname); + } + } + + jint channel = veData.base->CreateChannel(); + + return channel; +} + +///////////////////////////////////////////// +// [Base] Delete channel +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1DeleteChannel( + JNIEnv *, + jobject, + jint channel) + { + VALIDATE_BASE_POINTER; + return veData.base->DeleteChannel(channel); +} + +///////////////////////////////////////////// +// [Base] SetLocalReceiver +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetLocalReceiver( + JNIEnv *, + jobject, + jint channel, + jint port) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "SetLocalReceiver"); + VALIDATE_BASE_POINTER; + return veData.base->SetLocalReceiver(channel, port); +} + +///////////////////////////////////////////// +// [Base] SetSendDestination +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetSendDestination( + JNIEnv *env, + jobject, + jint channel, + jint port, + jstring ipaddr) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "SetSendDestination"); + VALIDATE_BASE_POINTER; + + const char* ipaddrNative = env->GetStringUTFChars(ipaddr, NULL); + if (!ipaddrNative) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Could not get UTF string"); + return -1; + } + jint retVal = veData.base->SetSendDestination(channel, port, ipaddrNative); + env->ReleaseStringUTFChars(ipaddr, ipaddrNative); + return retVal; +} + +///////////////////////////////////////////// +// [Base] StartListen +// +JNIEXPORT jint JNICALL Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StartListen( + JNIEnv *, + jobject, + jint channel) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "StartListen"); + VALIDATE_BASE_POINTER; + return veData.base->StartReceive(channel); +} + +///////////////////////////////////////////// +// [Base] Start playout +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StartPlayout( + JNIEnv *, + jobject, + jint channel) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "StartPlayout"); + VALIDATE_BASE_POINTER; + return veData.base->StartPlayout(channel); +} + +///////////////////////////////////////////// +// [Base] Start send +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StartSend( + JNIEnv *, + jobject, + jint channel) +{ + __android_log_write(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "StartSend"); + VALIDATE_BASE_POINTER; + return veData.base->StartSend(channel); +} + +///////////////////////////////////////////// +// [Base] Stop listen +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StopListen( + JNIEnv *, + jobject, + jint channel) +{ + VALIDATE_BASE_POINTER; + return veData.base->StartReceive(channel); +} + +///////////////////////////////////////////// +// [Base] Stop playout +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StopPlayout( + JNIEnv *, + jobject, + jint channel) +{ + VALIDATE_BASE_POINTER; + return veData.base->StopPlayout(channel); +} + +///////////////////////////////////////////// +// [Base] Stop send +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StopSend( + JNIEnv *, + jobject, + jint channel) +{ + VALIDATE_BASE_POINTER; + return veData.base->StopSend(channel); +} + +///////////////////////////////////////////// +// [codec] Number of codecs +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1NumOfCodecs( + JNIEnv *, + jobject) +{ + VALIDATE_CODEC_POINTER; + return veData.codec->NumOfCodecs(); +} + +///////////////////////////////////////////// +// [codec] Set send codec +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetSendCodec( + JNIEnv *, + jobject, + jint channel, + jint index) +{ + VALIDATE_CODEC_POINTER; + + webrtc::CodecInst codec; + + for (int i = 0; i < veData.codec->NumOfCodecs(); ++i) + { + webrtc::CodecInst codecToList; + veData.codec->GetCodec(i, codecToList); + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, + "VE Codec list %s, pltype=%d\n", + codecToList.plname, codecToList.pltype); + } + + if (veData.codec->GetCodec(index, codec) != 0) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Failed to get codec"); + return -1; + } + __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG, "SetSendCodec %s\n", + codec.plname); + + return veData.codec->SetSendCodec(channel, codec); +} + +///////////////////////////////////////////// +// [audioprocessing] SetNSStatus +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetNSStatus( + JNIEnv *, + jobject, + jboolean enable, + jint mode) +{ + //TODO implement + return -1; +} + +///////////////////////////////////////////// +// [audioprocessing] SetAGCStatus +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetAGCStatus( + JNIEnv *, + jobject, + jboolean enable, + jint mode) +{ + //TODO implement + return -1; +} + +///////////////////////////////////////////// +// [audioprocessing] SetECStatus +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetECStatus( + JNIEnv *, + jobject, + jboolean enable, + jint mode, + jint AESmode, + jint AESattenuation) +{ + //TODO implement + return -1; +} + +///////////////////////////////////////////// +// [File] Start play file locally +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StartPlayingFileLocally( + JNIEnv * env, + jobject, + jint channel, + jstring fileName, + jboolean loop) +{ + VALIDATE_FILE_POINTER; + + const char* fileNameNative = env->GetStringUTFChars(fileName, NULL); + if (!fileNameNative) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Could not get UTF string"); + return -1; + } + + jint retVal = veData.file->StartPlayingFileLocally(channel, fileNameNative, + loop); + + env->ReleaseStringUTFChars(fileName, fileNameNative); + + return retVal; +} + +///////////////////////////////////////////// +// [File] Stop play file locally +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_SVE_1StopPlayingFileLocally( + JNIEnv *, + jobject, + jint channel) +{ + VALIDATE_FILE_POINTER; + return veData.file->StopPlayingFileLocally(channel); +} + +///////////////////////////////////////////// +// [File] Start playing file as microphone +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StartPlayingFileAsMicrophone( + JNIEnv *env, + jobject, + jint channel, + jstring fileName, + jboolean loop) +{ + VALIDATE_FILE_POINTER; + + const char* fileNameNative = env->GetStringUTFChars(fileName, NULL); + if (!fileNameNative) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Could not get UTF string"); + return -1; + } + + jint retVal = veData.file->StartPlayingFileAsMicrophone(channel, + fileNameNative, + loop); + + env->ReleaseStringUTFChars(fileName, fileNameNative); + + return retVal; +} + +///////////////////////////////////////////// +// [File] Stop playing file as microphone +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1StopPlayingFileAsMicrophone( + JNIEnv *, + jobject, + jint channel) +{ + VALIDATE_FILE_POINTER; + return veData.file->StopPlayingFileAsMicrophone(channel); +} + +///////////////////////////////////////////// +// [Volume] Set speaker volume +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetSpeakerVolume( + JNIEnv *, + jobject, + jint level) +{ + VALIDATE_VOLUME_POINTER; + + if (veData.volume->SetSpeakerVolume(level) != 0) + { + return -1; + } + + unsigned int storedVolume = 0; + if (veData.volume->GetSpeakerVolume(storedVolume) != 0) + { + return -1; + } + + if (storedVolume != level) + { + return -1; + } + + return 0; +} + +///////////////////////////////////////////// +// [Hardware] Set speaker volume +// +JNIEXPORT jint JNICALL +Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_VE_1SetLoudspeakerStatus( + JNIEnv *, + jobject, + jboolean enable) +{ + VALIDATE_HARDWARE_POINTER; + + if (veData.hardware->SetLoudspeakerStatus(enable) != 0) + { + return -1; + } + + return 0; +} + +////////////////////////////////////////////////////////////////// +//local function +////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////// +// Get all sub-APIs +// +bool VE_GetSubApis() +{ + bool getOK = true; + + // Base + veData.base = VoEBase::GetInterface(veData.ve); + if (!veData.base) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get base sub-API failed"); + getOK = false; + } + + // Codec + veData.codec = VoECodec::GetInterface(veData.ve); + if (!veData.codec) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get codec sub-API failed"); + getOK = false; + } + + // File + veData.file = VoEFile::GetInterface(veData.ve); + if (!veData.file) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get file sub-API failed"); + getOK = false; + } + + // Network + veData.netw = VoENetwork::GetInterface(veData.ve); + if (!veData.netw) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get network sub-API failed"); + getOK = false; + } + + // audioprocessing + veData.apm = VoEAudioProcessing::GetInterface(veData.ve); + if (!veData.apm) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get VoEAudioProcessing sub-API failed"); + getOK = false; + } + + // Volume + veData.volume = VoEVolumeControl::GetInterface(veData.ve); + if (!veData.volume) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get volume sub-API failed"); + getOK = false; + } + + // Hardware + veData.hardware = VoEHardware::GetInterface(veData.ve); + if (!veData.hardware) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Get hardware sub-API failed"); + getOK = false; + } + + return getOK; +} + +///////////////////////////////////////////// +// Release all sub-APIs +// +bool VE_ReleaseSubApis() +{ + bool releaseOK = true; + + // Base + if (veData.base) + { + if (0 != veData.base->Release()) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Release base sub-API failed"); + releaseOK = false; + } + else + { + veData.base = NULL; + } + } + + // Codec + if (veData.codec) + { + if (0 != veData.codec->Release()) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Release codec sub-API failed"); + releaseOK = false; + } + else + { + veData.codec = NULL; + } + } + + // File + if (veData.file) + { + if (0 != veData.file->Release()) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Release file sub-API failed"); + releaseOK = false; + } + else + { + veData.file = NULL; + } + } + + // Network + if (veData.netw) + { + if (0 != veData.netw->Release()) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Release network sub-API failed"); + releaseOK = false; + } + else + { + veData.netw = NULL; + } + } + + // apm + if (veData.apm) + { + if (0 != veData.apm->Release()) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Release apm sub-API failed"); + releaseOK = false; + } + else + { + veData.apm = NULL; + } + } + + // Volume + if (veData.volume) + { + if (0 != veData.volume->Release()) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Release volume sub-API failed"); + releaseOK = false; + } + else + { + veData.volume = NULL; + } + } + + // Hardware + if (veData.hardware) + { + if (0 != veData.hardware->Release()) + { + __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, + "Release hardware sub-API failed"); + releaseOK = false; + } + else + { + veData.hardware = NULL; + } + } + + return releaseOK; +} diff --git a/video_engine/main/test/AndroidTest/res/drawable/logo.png b/video_engine/main/test/AndroidTest/res/drawable/logo.png new file mode 100644 index 0000000000..c3e0a123b5 Binary files /dev/null and b/video_engine/main/test/AndroidTest/res/drawable/logo.png differ diff --git a/video_engine/main/test/AndroidTest/res/layout/aconfig.xml b/video_engine/main/test/AndroidTest/res/layout/aconfig.xml new file mode 100644 index 0000000000..807ef69bab --- /dev/null +++ b/video_engine/main/test/AndroidTest/res/layout/aconfig.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/video_engine/main/test/AndroidTest/res/layout/both.xml b/video_engine/main/test/AndroidTest/res/layout/both.xml new file mode 100644 index 0000000000..d29d9063fc --- /dev/null +++ b/video_engine/main/test/AndroidTest/res/layout/both.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + diff --git a/video_engine/main/test/AutoTest/Android/res/values/strings.xml b/video_engine/main/test/AutoTest/Android/res/values/strings.xml new file mode 100644 index 0000000000..b06ef52734 --- /dev/null +++ b/video_engine/main/test/AutoTest/Android/res/values/strings.xml @@ -0,0 +1,31 @@ + + + +ViEAutotest +ViE Autotest Android +Run Test +Test type... + + Standard + API + Extended + Loopback + Custom + +Run... + + All + Base + Capture + Codec + Mix + Encryption + External Codec + File + Image Process + Network + Render + RTP/RTCP + + + diff --git a/video_engine/main/test/AutoTest/Android/src/org/webrtc/vieautotest/ViEAutotest.java b/video_engine/main/test/AutoTest/Android/src/org/webrtc/vieautotest/ViEAutotest.java new file mode 100644 index 0000000000..dc57e38f2a --- /dev/null +++ b/video_engine/main/test/AutoTest/Android/src/org/webrtc/vieautotest/ViEAutotest.java @@ -0,0 +1,159 @@ +package org.webrtc.vieautotest; + +import org.webrtc.vieautotest.R; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.widget.Button; +import android.view.SurfaceView; +import android.view.View; +import android.view.SurfaceHolder; +import android.widget.LinearLayout; +import android.opengl.GLSurfaceView; +import android.widget.Spinner; +import android.widget.ArrayAdapter; +import android.widget.AdapterView; + + +public class ViEAutotest extends Activity + implements + AdapterView.OnItemSelectedListener, + View.OnClickListener { + + private Thread _testThread; + private Spinner _testSpinner; + private Spinner _subtestSpinner; + private int _testSelection; + private int _subTestSelection; + + // View for remote video + private LinearLayout _remoteSurface = null; + private GLSurfaceView _glSurfaceView = null; + private SurfaceView _surfaceView = null; + + private LinearLayout _localSurface = null; + private GLSurfaceView _glLocalSurfaceView = null; + private SurfaceView _localSurfaceView = null; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + + Log.d("*WEBRTC*", "onCreate called"); + + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + // Set the Start button action + final Button buttonStart = (Button) findViewById(R.id.Button01); + buttonStart.setOnClickListener(this); + + // Set test spinner + _testSpinner = (Spinner) findViewById(R.id.testSpinner); + ArrayAdapter adapter = + ArrayAdapter.createFromResource(this, R.array.test_array, + android.R.layout.simple_spinner_item); + + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + _testSpinner.setAdapter(adapter); + _testSpinner.setOnItemSelectedListener(this); + + + // Set sub test spinner + _subtestSpinner = (Spinner) findViewById(R.id.subtestSpinner); + ArrayAdapter subtestAdapter = + ArrayAdapter.createFromResource(this, R.array.subtest_array, + android.R.layout.simple_spinner_item); + + subtestAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + _subtestSpinner.setAdapter(subtestAdapter); + _subtestSpinner.setOnItemSelectedListener(this); + + _remoteSurface = (LinearLayout) findViewById(R.id.RemoteView); + _surfaceView = new SurfaceView(this); + _remoteSurface.addView(_surfaceView); + + _localSurface = (LinearLayout) findViewById(R.id.LocalView); + _localSurfaceView = new SurfaceView(this); + _localSurfaceView.setZOrderMediaOverlay(true); + _localSurface.addView(_localSurfaceView); + + + // Set members + _testSelection = 0; + _subTestSelection = 0; + } + + public void onClick(View v) { + Log.d("*WEBRTC*", "Button clicked..."); + switch (v.getId()) { + case R.id.Button01: + + + new Thread(new Runnable() { + public void run() { + // + Log.d("*WEBRTC*", "Calling RunTest..."); + RunTest(_testSelection, _subTestSelection, _localSurfaceView, _surfaceView);// + Log.d("*WEBRTC*", "RunTest done"); + } + }).start(); + } + }; + + public void onItemSelected(AdapterView parent, View v, int position, long id) { + + if (parent == (Spinner) findViewById(R.id.testSpinner)) { + _testSelection = position; + } else { + _subTestSelection = position; + } + } + + public void onNothingSelected(AdapterView parent) { + ; + } + + @Override + protected void onStart() { + super.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + } + + @Override + protected void onDestroy() { + + super.onDestroy(); + } + + // C++ function performing the chosen test + // private native int RunTest(int testSelection, int subtestSelection, + // GLSurfaceView window1, GLSurfaceView window2); + private native int RunTest(int testSelection, int subtestSelection, SurfaceView window1, + SurfaceView window2); + + + /* + * this is used to load the 'ViEAutotestJNIAPI' library on application + * startup. + */ + static { + Log.d("*WEBRTC*", "Loading ViEAutotest..."); + System.loadLibrary("ViEAutotestJNIAPI"); + } +} diff --git a/video_engine/main/test/AutoTest/interface/tb_I420_codec.h b/video_engine/main/test/AutoTest/interface/tb_I420_codec.h new file mode 100644 index 0000000000..62559d4e59 --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/tb_I420_codec.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * tb_I420_codec.h + * + * This file contains the interface to I420 "codec" + * This is a dummy wrapper to allow VCM deal with raw I420 sequences + * + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_I420_CODEC_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_I420_CODEC_H_ + +#include "video_codec_interface.h" + +class tbI420Encoder: public webrtc::VideoEncoder +{ +public: + + tbI420Encoder(); + + virtual ~tbI420Encoder(); + + static WebRtc_Word32 VersionStatic(WebRtc_Word8* version, + WebRtc_Word32 length); + virtual WebRtc_Word32 Version(WebRtc_Word8 *version, + WebRtc_Word32 length) const; + + virtual WebRtc_Word32 InitEncode(const webrtc::VideoCodec* codecSettings, + WebRtc_Word32 numberOfCores, + WebRtc_UWord32 maxPayloadSize); + + virtual WebRtc_Word32 Encode(const webrtc::RawImage& inputImage, + const void* codecSpecificInfo = NULL, + webrtc::VideoFrameType frameType = + webrtc::kDeltaFrame); + + virtual WebRtc_Word32 RegisterEncodeCompleteCallback( + webrtc::EncodedImageCallback* callback); + + virtual WebRtc_Word32 Release(); + + virtual WebRtc_Word32 Reset(); + + virtual WebRtc_Word32 SetPacketLoss(WebRtc_UWord32 packetLoss); + + virtual WebRtc_Word32 SetRates(WebRtc_UWord32 newBitRate, + WebRtc_UWord32 frameRate); + + virtual WebRtc_Word32 SetPeriodicKeyFrames(bool enable); + + virtual WebRtc_Word32 CodecConfigParameters(WebRtc_UWord8* /*buffer*/, + WebRtc_Word32 /*size*/); + + struct FunctionCalls + { + WebRtc_Word32 InitEncode; + WebRtc_Word32 Encode; + WebRtc_Word32 RegisterEncodeCompleteCallback; + WebRtc_Word32 Release; + WebRtc_Word32 Reset; + WebRtc_Word32 SetRates; + WebRtc_Word32 SetPacketLoss; + WebRtc_Word32 SetPeriodicKeyFrames; + WebRtc_Word32 CodecConfigParameters; + + }; + + FunctionCalls GetFunctionCalls(); +private: + bool _inited; + webrtc::EncodedImage _encodedImage; + FunctionCalls _functionCalls; + webrtc::EncodedImageCallback* _encodedCompleteCallback; + +}; // end of tbI420Encoder class + + +/***************************/ +/* tbI420Decoder class */ +/***************************/ + +class tbI420Decoder: public webrtc::VideoDecoder +{ +public: + + tbI420Decoder(); + + virtual ~tbI420Decoder(); + + virtual WebRtc_Word32 InitDecode(const webrtc::VideoCodec* inst, + WebRtc_Word32 numberOfCores); + virtual WebRtc_Word32 Decode(const webrtc::EncodedImage& inputImage, + bool missingFrames, + const void* codecSpecificInfo = NULL, + WebRtc_Word64 renderTimeMs = -1); + virtual WebRtc_Word32 + RegisterDecodeCompleteCallback(webrtc::DecodedImageCallback* callback); + virtual WebRtc_Word32 Release(); + virtual WebRtc_Word32 Reset(); + + struct FunctionCalls + { + WebRtc_Word32 InitDecode; + WebRtc_Word32 Decode; + WebRtc_Word32 RegisterDecodeCompleteCallback; + WebRtc_Word32 Release; + WebRtc_Word32 Reset; + }; + + FunctionCalls GetFunctionCalls(); + +private: + + webrtc::RawImage _decodedImage; + WebRtc_Word32 _width; + WebRtc_Word32 _height; + bool _inited; + FunctionCalls _functionCalls; + webrtc::DecodedImageCallback* _decodeCompleteCallback; + +}; // end of tbI420Decoder class + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_I420_CODEC_H_ diff --git a/video_engine/main/test/AutoTest/interface/tb_capture_device.h b/video_engine/main/test/AutoTest/interface/tb_capture_device.h new file mode 100644 index 0000000000..44aa961de4 --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/tb_capture_device.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_CAPTURE_DEVICE_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_CAPTURE_DEVICE_H_ + +#include "tb_interfaces.h" +#include "video_capture.h" + +class tbCaptureDevice +{ +public: + tbCaptureDevice(tbInterfaces& Engine, int& nrOfErrors); + ~tbCaptureDevice(void); + + int captureId; + void ConnectTo(int videoChannel); + void Disconnect(int videoChannel); +private: + int& numberOfErrors; + tbInterfaces& ViE; + webrtc::VideoCaptureModule* vcpm_; +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_CAPTURE_DEVICE_H_ diff --git a/video_engine/main/test/AutoTest/interface/tb_external_transport.h b/video_engine/main/test/AutoTest/interface/tb_external_transport.h new file mode 100644 index 0000000000..a2f56af1c8 --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/tb_external_transport.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// tb_external_transport.h +// + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_EXTERNAL_TRANSPORT_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_EXTERNAL_TRANSPORT_H_ + +#include "common_types.h" +#include "list_wrapper.h" + +namespace webrtc +{ +class CriticalSectionWrapper; +class EventWrapper; +class ThreadWrapper; +class ViENetwork; +} + +class tbExternalTransport: public webrtc::Transport +{ +public: + tbExternalTransport(webrtc::ViENetwork& vieNetwork); + ~tbExternalTransport(void); + + virtual int SendPacket(int channel, const void *data, int len); + virtual int SendRTCPPacket(int channel, const void *data, int len); + + WebRtc_Word32 SetPacketLoss(WebRtc_Word32 lossRate); // Rate in % + void SetNetworkDelay(WebRtc_Word64 delayMs); + + void ClearStats(); + void GetStats(WebRtc_Word32& numRtpPackets, + WebRtc_Word32& numDroppedPackets, + WebRtc_Word32& numRtcpPackets); + + void EnableSSRCCheck(); + unsigned int ReceivedSSRC(); + + void EnableSequenceNumberCheck(); + unsigned short GetFirstSequenceNumber(); + +protected: + static bool ViEExternalTransportRun(void* object); + bool ViEExternalTransportProcess(); +private: + WebRtc_Word64 NowMs(); + + enum + { + KMaxPacketSize = 1650 + }; + enum + { + KMaxWaitTimeMs = 100 + }; + typedef struct + { + WebRtc_Word8 packetBuffer[KMaxPacketSize]; + WebRtc_Word32 length; + WebRtc_Word32 channel; + WebRtc_Word64 receiveTime; + } VideoPacket; + + webrtc::ViENetwork& _vieNetwork; + webrtc::ThreadWrapper& _thread; + webrtc::EventWrapper& _event; + webrtc::CriticalSectionWrapper& _crit; + webrtc::CriticalSectionWrapper& _statCrit; + + WebRtc_Word32 _lossRate; + WebRtc_Word64 _networkDelayMs; + WebRtc_Word32 _rtpCount; + WebRtc_Word32 _rtcpCount; + WebRtc_Word32 _dropCount; + + webrtc::ListWrapper _rtpPackets; + webrtc::ListWrapper _rtcpPackets; + + bool _checkSSRC; + WebRtc_UWord32 _lastSSRC; + bool _checkSequenceNumber; + WebRtc_UWord16 _firstSequenceNumber; +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_EXTERNAL_TRANSPORT_H_ diff --git a/video_engine/main/test/AutoTest/interface/tb_interfaces.h b/video_engine/main/test/AutoTest/interface/tb_interfaces.h new file mode 100644 index 0000000000..e03781593f --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/tb_interfaces.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_INTERFACES_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_INTERFACES_H_ + +#include "vie_autotest_defines.h" + +#include "common_types.h" +#include "vie_base.h" +#include "vie_capture.h" +#include "vie_codec.h" +#include "vie_image_process.h" +#include "vie_network.h" +#include "vie_render.h" +#include "vie_rtp_rtcp.h" +#include "vie_encryption.h" +#include "vie_defines.h" + +//using namespace webrtc; + +class tbInterfaces +{ +public: + tbInterfaces(const char* testName, int& nrOfErrors); + + ~tbInterfaces(void); + webrtc::VideoEngine* ptrViE; + webrtc::ViEBase* ptrViEBase; + webrtc::ViECapture* ptrViECapture; + webrtc::ViERender* ptrViERender; + webrtc::ViERTP_RTCP* ptrViERtpRtcp; + webrtc::ViECodec* ptrViECodec; + webrtc::ViENetwork* ptrViENetwork; + webrtc::ViEImageProcess* ptrViEImageProcess; + webrtc::ViEEncryption* ptrViEEncryption; + + int LastError() + { + return ptrViEBase->LastError(); + } + +private: + int& numberOfErrors; +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_INTERFACES_H_ diff --git a/video_engine/main/test/AutoTest/interface/tb_video_channel.h b/video_engine/main/test/AutoTest/interface/tb_video_channel.h new file mode 100644 index 0000000000..5c641444ab --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/tb_video_channel.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_VIDEO_CHANNEL_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_VIDEO_CHANNEL_H_ + +#include "tb_interfaces.h" +class tbVideoChannel +{ +public: + tbVideoChannel(tbInterfaces& Engine, int& nrOfErrors, + webrtc::VideoCodecType sendCodec = webrtc::kVideoCodecVP8, + int width = 352, int height = 288, int frameRate = 30, + int startBitrate = 300); + + ~tbVideoChannel(void); + + void SetFrameSettings(int width, int height, int frameRate); + + void StartSend(const unsigned short rtpPort = 11000, + const char* ipAddress = "127.0.0.1"); + + void StopSend(); + + void StartReceive(const unsigned short rtpPort = 11000); + + void StopReceive(); + + int videoChannel; +private: + int& numberOfErrors; + tbInterfaces& ViE; +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_TB_VIDEO_CHANNEL_H_ diff --git a/video_engine/main/test/AutoTest/interface/vie_autotest.h b/video_engine/main/test/AutoTest/interface/vie_autotest.h new file mode 100644 index 0000000000..96d2535a95 --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/vie_autotest.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest.h +// + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_H_ + +#include "common_types.h" + +#include "voe_base.h" +#include "voe_codec.h" +#include "voe_hardware.h" +#include "voe_audio_processing.h" + +#include "vie_base.h" +#include "vie_capture.h" +#include "vie_codec.h" +#include "vie_file.h" +#include "vie_network.h" +#include "vie_render.h" +#include "vie_rtp_rtcp.h" +#include "vie_defines.h" +#include "vie_errors.h" +#include "video_render_defines.h" + +#ifndef ANDROID +#include +#endif + +using namespace webrtc; + +class ViEAutoTest +{ +public: + ViEAutoTest(void* window1, void* window2); + ~ViEAutoTest(); + + int ViEStandardTest(); + int ViEExtendedTest(); + int ViEAPITest(); + int ViELoopbackCall(); + + // custom call and helper functions + int ViECustomCall(); + + // general settings functions + bool GetVideoDevice(ViEBase* ptrViEBase, ViECapture* ptrViECapture, + char* captureDeviceName, char* captureDeviceUniqueId); + bool GetIPAddress(char* IP); +#ifndef ANDROID + bool ValidateIP(std::string iStr); +#endif + void PrintCallInformation(char* IP, char* videoCaptureDeviceName, + char* videoCaptureUniqueId, + webrtc::VideoCodec videoCodec, int videoTxPort, + int videoRxPort, char* audioCaptureDeviceName, + char* audioPlaybackDeviceName, + webrtc::CodecInst audioCodec, int audioTxPort, + int audioRxPort); + + // video settings functions + bool GetVideoPorts(int* txPort, int* rxPort); + bool GetVideoCodec(ViECodec* ptrViECodec, webrtc::VideoCodec& videoCodec); + + // audio settings functions + bool GetAudioDevices(VoEBase* ptrVEBase, VoEHardware* ptrVEHardware, + char* recordingDeviceName, int& recordingDeviceIndex, + char* playbackDeviceName, int& playbackDeviceIndex); + bool GetAudioDevices(VoEBase* ptrVEBase, VoEHardware* ptrVEHardware, + int& recordingDeviceIndex, int& playbackDeviceIndex); + bool GetAudioPorts(int* txPort, int* rxPort); + bool GetAudioCodec(VoECodec* ptrVeCodec, CodecInst& audioCodec); + + // vie_autotest_base.cc + int ViEBaseStandardTest(); + int ViEBaseExtendedTest(); + int ViEBaseAPITest(); + + // vie_autotest_capture.cc + int ViECaptureStandardTest(); + int ViECaptureExtendedTest(); + int ViECaptureAPITest(); + int ViECaptureExternalCaptureTest(); + + // vie_autotest_codec.cc + int ViECodecStandardTest(); + int ViECodecExtendedTest(); + int ViECodecExternalCodecTest(); + int ViECodecAPITest(); + + // vie_autotest_encryption.cc + int ViEEncryptionStandardTest(); + int ViEEncryptionExtendedTest(); + int ViEEncryptionAPITest(); + + // vie_autotest_file.ccs + int ViEFileStandardTest(); + int ViEFileExtendedTest(); + int ViEFileAPITest(); + + // vie_autotest_image_process.cc + int ViEImageProcessStandardTest(); + int ViEImageProcessExtendedTest(); + int ViEImageProcessAPITest(); + + // vie_autotest_network.cc + int ViENetworkStandardTest(); + int ViENetworkExtendedTest(); + int ViENetworkAPITest(); + + // vie_autotest_render.cc + int ViERenderStandardTest(); + int ViERenderExtendedTest(); + int ViERenderAPITest(); + + // vie_autotest_rtp_rtcp.cc + int ViERtpRtcpStandardTest(); + int ViERtpRtcpExtendedTest(); + int ViERtpRtcpAPITest(); + +private: + void PrintAudioCodec(const webrtc::CodecInst audioCodec); + void PrintVideoCodec(const webrtc::VideoCodec videoCodec); + + void* _window1; + void* _window2; + + VideoRenderType _renderType; + VideoRender* _vrm1; + VideoRender* _vrm2; +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_H_ diff --git a/video_engine/main/test/AutoTest/interface/vie_autotest_android.h b/video_engine/main/test/AutoTest/interface/vie_autotest_android.h new file mode 100644 index 0000000000..53b8cc31bf --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/vie_autotest_android.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_ANDROID_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_ANDROID_H_ + +class ViEAutoTestAndroid +{ +public: + static int RunAutotest(int testSelection, + int subTestSelection, + void* window1, + void* window2, + void* javaVM, + void* env, + void* context); +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_ANDROID_H_ diff --git a/video_engine/main/test/AutoTest/interface/vie_autotest_defines.h b/video_engine/main/test/AutoTest/interface/vie_autotest_defines.h new file mode 100644 index 0000000000..b8ff7eae92 --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/vie_autotest_defines.h @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_defines.h +// + + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_DEFINES_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_DEFINES_H_ + +#include +#include +#include + +#include "engine_configurations.h" + +#if defined(_WIN32) +#include +#elif defined (ANDROID) +#include +#include +#elif defined(WEBRTC_LINUX) +#include +#include +#include +#include +#elif defined(WEBRTC_MAC_INTEL) +#import +#endif + +// Choose how to log +//#define VIE_LOG_TO_FILE +#define VIE_LOG_TO_STDOUT + +// Choose one way to test error +#define VIE_ASSERT_ERROR + +#define VIE_LOG_FILE_NAME "ViEAutotestLog.txt" + +#undef RGB +#define RGB(r,g,b) r|g<<8|b<<16 + +// Default values for custom call +#define DEFAULT_SEND_IP "127.0.0.1" +#define DEFAULT_VIDEO_PORT 9000 +#define DEFAULT_VIDEO_CODEC "vp8" +#define DEFAULT_VIDEO_CODEC_WIDTH 352 +#define DEFAULT_VIDEO_CODEC_HEIGHT 288 +#define DEFAULT_AUDIO_PORT 8000 +#define DEFAULT_AUDIO_CODEC "isac" + +enum +{ + KAutoTestSleepTimeMs = 5000 +}; + +struct AutoTestSize +{ + unsigned int width; + unsigned int height; + AutoTestSize() : + width(0), + height(0) + {} + AutoTestSize(unsigned int iWidth, unsigned int iHeight) : + width(iWidth), + height(iHeight) + {} +}; + +struct AutoTestOrigin +{ + unsigned int x; + unsigned int y; + AutoTestOrigin() : + x(0), + y(0) + {} + AutoTestOrigin(unsigned int iX, unsigned int iY) : + x(iX), + y(iY) + {} +}; + +struct AutoTestRect +{ + AutoTestSize size; + AutoTestOrigin origin; + AutoTestRect() : + size(), + origin() + {} + + AutoTestRect(unsigned int iX, unsigned int iY, unsigned int iWidth, + unsigned int iHeight) : + size(iX, iY), + origin(iWidth, iHeight) + {} + + void Copy(AutoTestRect iRect) + { + origin.x = iRect.origin.x; + origin.y = iRect.origin.y; + size.width = iRect.size.width; + size.height = iRect.size.height; + } +}; + +// ============================================ + +class ViETest +{ +protected: + static FILE* _logFile; + enum + { + KMaxLogSize = 512 + }; + static char* _logStr; +public: + + static int Init() + { +#ifdef VIE_LOG_TO_FILE + _logFile = fopen(VIE_LOG_FILE_NAME, "w+t"); +#else + _logFile = NULL; +#endif + _logStr = new char[KMaxLogSize]; + memset(_logStr, 0, KMaxLogSize); + return 0; + } + + static int Terminate() + { + if (_logFile) + { + fclose(_logFile); + _logFile = NULL; + } + if (_logStr) + { + delete[] _logStr; + _logStr = NULL; + } + return 0; + } + + static void Log(char* fmt, ...) + { + va_list va; + va_start(va, fmt); + memset(_logStr, 0, KMaxLogSize); + vsprintf(_logStr, fmt, va); + va_end(va); + +#ifdef VIE_LOG_TO_FILE + if (_logFile) + { + fwrite(_logStr, 1, strlen(_logStr), _logFile); + fwrite("\n", 1, 1, _logFile); + fflush(_logFile); + } +#endif +#ifdef VIE_LOG_TO_STDOUT +#if ANDROID + __android_log_write(ANDROID_LOG_DEBUG, "*WebRTCN*", _logStr); +#else + printf(_logStr); + printf("\n"); +#endif +#endif + } + + static int TestError(bool expr) + { + if (!expr) + { +#ifdef VIE_ASSERT_ERROR + assert(expr); +#endif + return 1; + } + return 0; + } + + static int TestError(bool expr, char* fmt, ...) + { + + if (!expr) + { + va_list va; + va_start(va, fmt); + memset(_logStr, 0, KMaxLogSize); + vsprintf(_logStr, fmt, va); +#ifdef ANDROID + __android_log_write(ANDROID_LOG_ERROR, "*WebRTCN*", _logStr); +#endif + Log(_logStr); + va_end(va); + +#ifdef VIE_ASSERT_ERROR + assert(false); +#endif + return 1; + } + return 0; + } +}; + +// milliseconds +#if defined(_WIN32) +#define AutoTestSleep ::Sleep +#elif defined(WEBRTC_MAC_INTEL) +#define AutoTestSleep(x) usleep(x * 1000) +#elif defined(WEBRTC_LINUX) +namespace +{ + void Sleep(unsigned long x) + { + timespec t; + t.tv_sec = x/1000; + t.tv_nsec = (x-(x/1000)*1000)*1000000; + nanosleep(&t,NULL); + } +} +#define AutoTestSleep ::Sleep +#endif + +#ifdef ANDROID +#define VIE_TEST_FILES_ROOT "/sdcard/vie_auto_test/" +#else +#define VIE_TEST_FILES_ROOT "/tmp/vie_auto_test/" +#endif + +namespace +{ +FILE* OpenTestFile(char* fileName) +{ + char filePath[256]; + sprintf(filePath,"%s%s",VIE_TEST_FILES_ROOT,fileName); + return fopen(filePath,"rb"); +} +} +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_DEFINES_H_ diff --git a/video_engine/main/test/AutoTest/interface/vie_autotest_linux.h b/video_engine/main/test/AutoTest/interface/vie_autotest_linux.h new file mode 100644 index 0000000000..5343eb6a19 --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/vie_autotest_linux.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_LINUX_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_LINUX_H_ + +#include "vie_autotest_window_manager_interface.h" +#include +#include + +// Forward declaration + +class ViEAutoTestWindowManager: public ViEAutoTestWindowManagerInterface +{ +public: + ViEAutoTestWindowManager(); + ~ViEAutoTestWindowManager(); + virtual void* GetWindow1(); + virtual void* GetWindow2(); + virtual int TerminateWindows(); + virtual int CreateWindows(AutoTestRect window1Size, + AutoTestRect window2Size, void* window1Title, + void* window2Title); + virtual bool SetTopmostWindow(); + +private: + int ViECreateWindow(Window *outWindow, Display **outDisplay, int xpos, + int ypos, int width, int height, char* title); + int ViEDestroyWindow(Window *window, Display *display); + + Window _hwnd1; + Window _hwnd2; + Display* _hdsp1; + Display* _hdsp2; +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_LINUX_H_ diff --git a/video_engine/main/test/AutoTest/interface/vie_autotest_mac_carbon.h b/video_engine/main/test/AutoTest/interface/vie_autotest_mac_carbon.h new file mode 100644 index 0000000000..a67806a267 --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/vie_autotest_mac_carbon.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "EngineConfigurations.h" + +#if defined(CARBON_RENDERING) +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_MAC_CARBON_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_MAC_CARBON_H_ + +#include "vie_autotest_window_manager_interface.h" + +// #define HIVIEWREF_MODE 1 + +#include +#import + +class ViEAutoTestWindowManager: public ViEAutoTestWindowManagerInterface +{ +public: + ViEAutoTestWindowManager(); + ~ViEAutoTestWindowManager(); + virtual void* GetWindow1(); + virtual void* GetWindow2(); + virtual int CreateWindows(AutoTestRect window1Size, + AutoTestRect window2Size, char* window1Title, + char* window2Title); + virtual int TerminateWindows(); + virtual bool SetTopmostWindow(); + + // event handler static methods +static pascal OSStatus HandleWindowEvent (EventHandlerCallRef nextHandler, + EventRef theEvent, void* userData); +static pascal OSStatus HandleHIViewEvent (EventHandlerCallRef nextHandler, + EventRef theEvent, void* userData); +private: + WindowRef* _carbonWindow1; + WindowRef* _carbonWindow2; + HIViewRef* _hiView1; + HIViewRef* _hiView2; + + EventHandlerRef _carbonWindow1EventHandlerRef; + EventHandlerRef _carbonWindow2EventHandlerRef; + EventHandlerRef _carbonHIView1EventHandlerRef; + EventHandlerRef _carbonHIView2EventHandlerRef; + +}; + +@interface AutoTestClass : NSObject +{ +} + +-(void)autoTestWithArg:(NSString*)answerFile; +@end + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_MAC_CARBON_H_ +#endif CARBON_RENDERING diff --git a/video_engine/main/test/AutoTest/interface/vie_autotest_mac_cocoa.h b/video_engine/main/test/AutoTest/interface/vie_autotest_mac_cocoa.h new file mode 100644 index 0000000000..c131649b40 --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/vie_autotest_mac_cocoa.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "engine_configurations.h" + +#if defined(COCOA_RENDERING) + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_MAC_COCOA_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_MAC_COCOA_H_ + +#include "vie_autotest_window_manager_interface.h" +#define MAC_COCOA_USE_NSRUNLOOP 1 + +@class CocoaRenderView; + +#import + +class ViEAutoTestWindowManager: public ViEAutoTestWindowManagerInterface +{ +public: + ViEAutoTestWindowManager(); + ~ViEAutoTestWindowManager(); + virtual void* GetWindow1(); + virtual void* GetWindow2(); + virtual int CreateWindows(AutoTestRect window1Size, + AutoTestRect window2Size, void* window1Title, + void* window2Title); + virtual int TerminateWindows(); + virtual bool SetTopmostWindow(); + +private: + CocoaRenderView* _cocoaRenderView1; + CocoaRenderView* _cocoaRenderView2; +}; + +@interface AutoTestClass : NSObject +{ +} + +-(void)autoTestWithArg:(NSString*)answerFile; + +@end + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_MAC_COCOA_H_ +#endif // COCOA_RENDERING diff --git a/video_engine/main/test/AutoTest/interface/vie_autotest_main.h b/video_engine/main/test/AutoTest/interface/vie_autotest_main.h new file mode 100644 index 0000000000..43ce358159 --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/vie_autotest_main.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_MAIN_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_MAIN_H_ + +#include + +using namespace std; + +class ViEAutoTestMain +{ +public: + ViEAutoTestMain(); + bool BeginOSIndependentTesting(); + bool GetAnswer(int index, string& answer); + int GetClassTestSelection(); + bool GetNextAnswer(string& answer); + bool IsUsingAnswerFile(); + bool UseAnswerFile(const char* fileName); + +private: + + string _answers[1024]; + int _answersCount; + int _answersIndex; + bool _useAnswerFile; +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_MAIN_H_ diff --git a/video_engine/main/test/AutoTest/interface/vie_autotest_window_manager_interface.h b/video_engine/main/test/AutoTest/interface/vie_autotest_window_manager_interface.h new file mode 100644 index 0000000000..04a3676751 --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/vie_autotest_window_manager_interface.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_autotest_window_manager_interface.h + */ + +#include "vie_autotest_defines.h" + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_WINDOW_MANAGER_INTERFACE_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_WINDOW_MANAGER_INTERFACE_H_ + +class ViEAutoTestWindowManagerInterface +{ +public: + virtual int CreateWindows(AutoTestRect window1Size, + AutoTestRect window2Size, void* window1Title, + void* window2Title) = 0; + virtual int TerminateWindows() = 0; + virtual void* GetWindow1() = 0; + virtual void* GetWindow2() = 0; + virtual bool SetTopmostWindow() = 0; +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_WINDOW_MANAGER_INTERFACE_H_ diff --git a/video_engine/main/test/AutoTest/interface/vie_autotest_windows.h b/video_engine/main/test/AutoTest/interface/vie_autotest_windows.h new file mode 100644 index 0000000000..584e75c2ee --- /dev/null +++ b/video_engine/main/test/AutoTest/interface/vie_autotest_windows.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_WINDOWS_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_WINDOWS_H_ + +#include "vie_autotest_window_manager_interface.h" +#include "engine_configurations.h" + +#include +#define TITLE_LENGTH 1024 + +// Forward declaration +namespace webrtc { +class ThreadWrapper; +class CriticalSectionWrapper; +} + +class ViEAutoTestWindowManager: public ViEAutoTestWindowManagerInterface +{ +public: + ViEAutoTestWindowManager(); + ~ViEAutoTestWindowManager(); + virtual void* GetWindow1(); + virtual void* GetWindow2(); + virtual int CreateWindows(AutoTestRect window1Size, + AutoTestRect window2Size, void* window1Title, + void* window2Title); + virtual int TerminateWindows(); + virtual bool SetTopmostWindow(); +protected: + static bool EventProcess(void* obj); + bool EventLoop(); + +private: + int ViECreateWindow(HWND &hwndMain, int xPos, int yPos, int width, + int height, TCHAR* className); + int ViEDestroyWindow(HWND& hwnd); + + void* _window1; + void* _window2; + + bool _terminate; + webrtc::ThreadWrapper& _eventThread; + webrtc::CriticalSectionWrapper& _crit; + HWND _hwndMain; + HWND _hwnd1; + HWND _hwnd2; + + AutoTestRect _hwnd1Size; + AutoTestRect _hwnd2Size; + TCHAR _hwnd1Title[TITLE_LENGTH]; + TCHAR _hwnd2Title[TITLE_LENGTH]; + +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_AUTOTEST_INTERFACE_VIE_AUTOTEST_WINDOWS_H_ diff --git a/video_engine/main/test/AutoTest/media/captureDeviceImage.bmp b/video_engine/main/test/AutoTest/media/captureDeviceImage.bmp new file mode 100644 index 0000000000..6cd34ba97e Binary files /dev/null and b/video_engine/main/test/AutoTest/media/captureDeviceImage.bmp differ diff --git a/video_engine/main/test/AutoTest/media/captureDeviceImage.jpg b/video_engine/main/test/AutoTest/media/captureDeviceImage.jpg new file mode 100644 index 0000000000..3bb3ba48bb Binary files /dev/null and b/video_engine/main/test/AutoTest/media/captureDeviceImage.jpg differ diff --git a/video_engine/main/test/AutoTest/media/renderStartImage.bmp b/video_engine/main/test/AutoTest/media/renderStartImage.bmp new file mode 100644 index 0000000000..c443a58f6c Binary files /dev/null and b/video_engine/main/test/AutoTest/media/renderStartImage.bmp differ diff --git a/video_engine/main/test/AutoTest/media/renderStartImage.jpg b/video_engine/main/test/AutoTest/media/renderStartImage.jpg new file mode 100644 index 0000000000..b10a84259c Binary files /dev/null and b/video_engine/main/test/AutoTest/media/renderStartImage.jpg differ diff --git a/video_engine/main/test/AutoTest/media/renderTimeoutImage.bmp b/video_engine/main/test/AutoTest/media/renderTimeoutImage.bmp new file mode 100644 index 0000000000..8159badeb2 Binary files /dev/null and b/video_engine/main/test/AutoTest/media/renderTimeoutImage.bmp differ diff --git a/video_engine/main/test/AutoTest/media/renderTimeoutImage.jpg b/video_engine/main/test/AutoTest/media/renderTimeoutImage.jpg new file mode 100644 index 0000000000..cb34d67664 Binary files /dev/null and b/video_engine/main/test/AutoTest/media/renderTimeoutImage.jpg differ diff --git a/video_engine/main/test/AutoTest/source/tb_I420_codec.cc b/video_engine/main/test/AutoTest/source/tb_I420_codec.cc new file mode 100644 index 0000000000..cdbc244d53 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/tb_I420_codec.cc @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * tb_I420_codec.cc + * + */ + +#include "tb_I420_codec.h" +#include +#include +#include + +tbI420Encoder::tbI420Encoder() : + _inited(false), _encodedImage(), _encodedCompleteCallback(NULL) +{ + // + memset(&_functionCalls, 0, sizeof(_functionCalls)); +} + +tbI420Encoder::~tbI420Encoder() +{ + _inited = false; + if (_encodedImage._buffer != NULL) + { + delete[] _encodedImage._buffer; + _encodedImage._buffer = NULL; + } +} + +WebRtc_Word32 tbI420Encoder::VersionStatic(WebRtc_Word8* version, + WebRtc_Word32 length) +{ + const WebRtc_Word8* str = "I420 version 1.0.0\n"; + WebRtc_Word32 verLen = (WebRtc_Word32) strlen(str); + if (verLen > length) + { + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + } + strncpy(version, str, length); + return verLen; +} + +WebRtc_Word32 tbI420Encoder::Version(WebRtc_Word8 *version, + WebRtc_Word32 length) const +{ + return VersionStatic(version, length); +} + +WebRtc_Word32 tbI420Encoder::Release() +{ + _functionCalls.Release++; + // should allocate an encoded frame and then release it here, for that we + // actaully need an init flag + if (_encodedImage._buffer != NULL) + { + delete[] _encodedImage._buffer; + _encodedImage._buffer = NULL; + } + _inited = false; + return WEBRTC_VIDEO_CODEC_OK; +} + +WebRtc_Word32 tbI420Encoder::Reset() +{ + _functionCalls.Reset++; + if (!_inited) + { + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + return WEBRTC_VIDEO_CODEC_OK; + +} + +WebRtc_Word32 tbI420Encoder::InitEncode(const webrtc::VideoCodec* inst, + WebRtc_Word32 /*numberOfCores*/, + WebRtc_UWord32 /*maxPayloadSize */) +{ + _functionCalls.InitEncode++; + if (inst == NULL) + { + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + } + if (inst->width < 1 || inst->height < 1) + { + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + } + + // allocating encoded memory + if (_encodedImage._buffer != NULL) + { + delete[] _encodedImage._buffer; + _encodedImage._buffer = NULL; + _encodedImage._size = 0; + } + const WebRtc_UWord32 newSize = (3 * inst->width * inst->height) >> 1; + WebRtc_UWord8* newBuffer = new WebRtc_UWord8[newSize]; + if (newBuffer == NULL) + { + return WEBRTC_VIDEO_CODEC_MEMORY; + } + _encodedImage._size = newSize; + _encodedImage._buffer = newBuffer; + + // if no memeory allocation, no point to init + _inited = true; + return WEBRTC_VIDEO_CODEC_OK; +} + +WebRtc_Word32 tbI420Encoder::Encode(const webrtc::RawImage& inputImage, + const void* codecSpecificInfo /*= NULL*/, + webrtc::VideoFrameType frameType + /*= webrtc::kDeltaFrame*/) +{ + _functionCalls.Encode++; + if (!_inited) + { + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + if (_encodedCompleteCallback == NULL) + { + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + + _encodedImage._frameType = webrtc::kKeyFrame; // no coding + _encodedImage._timeStamp = inputImage._timeStamp; + _encodedImage._encodedHeight = inputImage._height; + _encodedImage._encodedWidth = inputImage._width; + if (inputImage._length > _encodedImage._size) + { + + // allocating encoded memory + if (_encodedImage._buffer != NULL) + { + delete[] _encodedImage._buffer; + _encodedImage._buffer = NULL; + _encodedImage._size = 0; + } + const WebRtc_UWord32 newSize = (3 * _encodedImage._encodedWidth + * _encodedImage._encodedHeight) >> 1; + WebRtc_UWord8* newBuffer = new WebRtc_UWord8[newSize]; + if (newBuffer == NULL) + { + return WEBRTC_VIDEO_CODEC_MEMORY; + } + _encodedImage._size = newSize; + _encodedImage._buffer = newBuffer; + } + assert(_encodedImage._size >= inputImage._length); + memcpy(_encodedImage._buffer, inputImage._buffer, inputImage._length); + _encodedImage._length = inputImage._length; + _encodedCompleteCallback->Encoded(_encodedImage); + return WEBRTC_VIDEO_CODEC_OK; +} + +WebRtc_Word32 tbI420Encoder::RegisterEncodeCompleteCallback( + webrtc::EncodedImageCallback* callback) +{ + _functionCalls.RegisterEncodeCompleteCallback++; + _encodedCompleteCallback = callback; + return WEBRTC_VIDEO_CODEC_OK; +} + +WebRtc_Word32 tbI420Encoder::SetPacketLoss(WebRtc_UWord32 packetLoss) +{ + _functionCalls.SetPacketLoss++; + return WEBRTC_VIDEO_CODEC_OK; +} + +WebRtc_Word32 tbI420Encoder::SetRates(WebRtc_UWord32 newBitRate, + WebRtc_UWord32 frameRate) +{ + _functionCalls.SetRates++; + return WEBRTC_VIDEO_CODEC_OK; +} + +WebRtc_Word32 tbI420Encoder::SetPeriodicKeyFrames(bool enable) +{ + _functionCalls.SetPeriodicKeyFrames++; + return WEBRTC_VIDEO_CODEC_ERROR; +} + +WebRtc_Word32 tbI420Encoder::CodecConfigParameters(WebRtc_UWord8* /*buffer*/, + WebRtc_Word32 /*size*/) +{ + _functionCalls.CodecConfigParameters++; + return WEBRTC_VIDEO_CODEC_ERROR; +} +tbI420Encoder::FunctionCalls tbI420Encoder::GetFunctionCalls() +{ + return _functionCalls; +} + +tbI420Decoder::tbI420Decoder(): + _decodedImage(), _width(0), _height(0), _inited(false), + _decodeCompleteCallback(NULL) +{ + memset(&_functionCalls, 0, sizeof(_functionCalls)); +} + +tbI420Decoder::~tbI420Decoder() +{ + Release(); +} + +WebRtc_Word32 tbI420Decoder::Reset() +{ + _functionCalls.Reset++; + return WEBRTC_VIDEO_CODEC_OK; +} + +WebRtc_Word32 tbI420Decoder::InitDecode(const webrtc::VideoCodec* inst, + WebRtc_Word32 /*numberOfCores */) +{ + _functionCalls.InitDecode++; + if (inst == NULL) + { + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + } + else if (inst->width < 1 || inst->height < 1) + { + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + } + _width = inst->width; + _height = inst->height; + _inited = true; + return WEBRTC_VIDEO_CODEC_OK; +} + +WebRtc_Word32 tbI420Decoder::Decode(const webrtc::EncodedImage& inputImage, + bool /*missingFrames*/, + const void* /*codecSpecificInfWord64o*/, + WebRtc_Word64 /*renderTimeMs*/) +{ + _functionCalls.Decode++; + if (inputImage._buffer == NULL) + { + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + } + if (_decodeCompleteCallback == NULL) + { + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + if (inputImage._length <= 0) + { + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + } + if (!_inited) + { + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + + // Allocate memory for decoded image + + if (_decodedImage._buffer != NULL) + { + delete[] _decodedImage._buffer; + _decodedImage._buffer = NULL; + _decodedImage._size = 0; + } + if (_decodedImage._buffer == NULL) + { + const WebRtc_UWord32 newSize = (3 * _width * _height) >> 1; + WebRtc_UWord8* newBuffer = new WebRtc_UWord8[newSize]; + if (newBuffer == NULL) + { + return WEBRTC_VIDEO_CODEC_MEMORY; + } + _decodedImage._size = newSize; + _decodedImage._buffer = newBuffer; + } + + // Set decoded image parameters + _decodedImage._height = _height; + _decodedImage._width = _width; + _decodedImage._timeStamp = inputImage._timeStamp; + assert(_decodedImage._size >= inputImage._length); + memcpy(_decodedImage._buffer, inputImage._buffer, inputImage._length); + _decodedImage._length = inputImage._length; + //_decodedImage._buffer = inputImage._buffer; + + _decodeCompleteCallback->Decoded(_decodedImage); + return WEBRTC_VIDEO_CODEC_OK; +} + +WebRtc_Word32 tbI420Decoder::RegisterDecodeCompleteCallback( + webrtc::DecodedImageCallback* callback) +{ + _functionCalls.RegisterDecodeCompleteCallback++; + _decodeCompleteCallback = callback; + return WEBRTC_VIDEO_CODEC_OK; +} + +WebRtc_Word32 tbI420Decoder::Release() +{ + _functionCalls.Release++; + if (_decodedImage._buffer != NULL) + { + delete[] _decodedImage._buffer; + _decodedImage._buffer = NULL; + } + _inited = false; + return WEBRTC_VIDEO_CODEC_OK; +} + +tbI420Decoder::FunctionCalls tbI420Decoder::GetFunctionCalls() +{ + return _functionCalls; +} + diff --git a/video_engine/main/test/AutoTest/source/tb_capture_device.cc b/video_engine/main/test/AutoTest/source/tb_capture_device.cc new file mode 100644 index 0000000000..297a00b23f --- /dev/null +++ b/video_engine/main/test/AutoTest/source/tb_capture_device.cc @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "tb_capture_device.h" + +tbCaptureDevice::tbCaptureDevice(tbInterfaces& Engine, int& nrOfErrors) : + ViE(Engine), + numberOfErrors(nrOfErrors), + captureId(-1), + vcpm_(NULL) +{ + const unsigned int KMaxDeviceNameLength = 128; + const unsigned int KMaxUniqueIdLength = 256; + WebRtc_UWord8 deviceName[KMaxDeviceNameLength]; + memset(deviceName, 0, KMaxDeviceNameLength); + WebRtc_UWord8 uniqueId[KMaxUniqueIdLength]; + memset(uniqueId, 0, KMaxUniqueIdLength); + + int error; + bool captureDeviceSet = false; + + webrtc::VideoCaptureModule::DeviceInfo* devInfo = + webrtc::VideoCaptureModule::CreateDeviceInfo(0); + for (size_t captureIdx = 0; + captureIdx < devInfo->NumberOfDevices(); + captureIdx++) + { + error = devInfo->GetDeviceName(captureIdx, deviceName, + KMaxDeviceNameLength, uniqueId, + KMaxUniqueIdLength); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + vcpm_ = webrtc::VideoCaptureModule::Create(captureIdx, uniqueId); + if (vcpm_ == NULL) // Failed to open this device. Try next. + { + continue; + } + + error = ViE.ptrViECapture->AllocateCaptureDevice(*vcpm_, captureId); + if (error == 0) + { + ViETest::Log("Using capture device: %s, captureId: %d", deviceName, + captureId); + captureDeviceSet = true; + break; + } + } + webrtc::VideoCaptureModule::DestroyDeviceInfo(devInfo); + numberOfErrors += ViETest::TestError( + captureDeviceSet, "ERROR: %s at line %d - Could not set capture device", + __FUNCTION__, __LINE__); + + ViETest::Log("Starting capture device %s with captureId %d\n", deviceName, + captureId); + + error = ViE.ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +} + +tbCaptureDevice::~tbCaptureDevice(void) +{ + ViETest::Log("Stopping capture device with id %d\n", captureId); + int error; + error = ViE.ptrViECapture->StopCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViECapture->ReleaseCaptureDevice(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + webrtc::VideoCaptureModule::Destroy(vcpm_); + +} + +void tbCaptureDevice::ConnectTo(int videoChannel) +{ + int error; + error = ViE.ptrViECapture->ConnectCaptureDevice(captureId, videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +} + +void tbCaptureDevice::Disconnect(int videoChannel) +{ + int error = 0; + error = ViE.ptrViECapture->DisconnectCaptureDevice(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +} diff --git a/video_engine/main/test/AutoTest/source/tb_external_transport.cc b/video_engine/main/test/AutoTest/source/tb_external_transport.cc new file mode 100644 index 0000000000..35d7a95ac9 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/tb_external_transport.cc @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// tb_external_transport.cc +// + +#include // rand +#include "tb_external_transport.h" + +#include "critical_section_wrapper.h" +#include "event_wrapper.h" +#include "thread_wrapper.h" +#include "tick_util.h" +#include "vie_network.h" +#include "tick_util.h" + +#if defined(WEBRTC_LINUX) || defined(__linux__) +#include +#include +#endif + +#if defined(WEBRTC_MAC) +#include +#endif + +#if defined(_WIN32) +#pragma warning(disable: 4355) // 'this' : used in base member initializer list +#endif + +using namespace webrtc; + +tbExternalTransport::tbExternalTransport(ViENetwork& vieNetwork) : + _vieNetwork(vieNetwork), + _thread(*ThreadWrapper::CreateThread(ViEExternalTransportRun, this, + kHighPriority, + "AutotestTransport")), + _event(*EventWrapper::Create()), + _crit(*CriticalSectionWrapper::CreateCriticalSection()), + _statCrit(*CriticalSectionWrapper::CreateCriticalSection()), + _lossRate(0), _networkDelayMs(0), _rtpCount(0), _rtcpCount(0), + _dropCount(0), _rtpPackets(), _rtcpPackets(), _checkSSRC(false), + _lastSSRC(0), _checkSequenceNumber(0), _firstSequenceNumber(0) +{ + srand((int) TickTime::MicrosecondTimestamp()); + unsigned int tId = 0; + _thread.Start(tId); +} + +tbExternalTransport::~tbExternalTransport() +{ + _thread.SetNotAlive(); + _event.Set(); + if (_thread.Stop()) + { + delete &_thread; + delete &_event; + } + delete &_crit; + delete &_statCrit; +} + +int tbExternalTransport::SendPacket(int channel, const void *data, int len) +{ + _statCrit.Enter(); + _rtpCount++; + _statCrit.Leave(); + + // Packet loss + int dropThis = rand() % 100; + if (dropThis < _lossRate) + { + _statCrit.Enter(); + _dropCount++; + _statCrit.Leave(); + return 0; + } + + VideoPacket* newPacket = new VideoPacket(); + memcpy(newPacket->packetBuffer, data, len); + newPacket->length = len; + newPacket->channel = channel; + + _crit.Enter(); + newPacket->receiveTime = NowMs() + _networkDelayMs; + _rtpPackets.PushBack(newPacket); + _event.Set(); + _crit.Leave(); + return len; +} + +int tbExternalTransport::SendRTCPPacket(int channel, const void *data, int len) +{ + _statCrit.Enter(); + _rtcpCount++; + _statCrit.Leave(); + + VideoPacket* newPacket = new VideoPacket(); + memcpy(newPacket->packetBuffer, data, len); + newPacket->length = len; + newPacket->channel = channel; + + _crit.Enter(); + newPacket->receiveTime = NowMs() + _networkDelayMs; + _rtcpPackets.PushBack(newPacket); + _event.Set(); + _crit.Leave(); + return len; +} + +WebRtc_Word32 tbExternalTransport::SetPacketLoss(WebRtc_Word32 lossRate) +{ + CriticalSectionScoped cs(_statCrit); + _lossRate = lossRate; + return 0; +} + +void tbExternalTransport::SetNetworkDelay(WebRtc_Word64 delayMs) +{ + CriticalSectionScoped cs(_crit); + _networkDelayMs = delayMs; + return; +} + +void tbExternalTransport::ClearStats() +{ + CriticalSectionScoped cs(_statCrit); + _rtpCount = 0; + _dropCount = 0; + _rtcpCount = 0; + return; +} + +void tbExternalTransport::GetStats(WebRtc_Word32& numRtpPackets, + WebRtc_Word32& numDroppedPackets, + WebRtc_Word32& numRtcpPackets) +{ + CriticalSectionScoped cs(_statCrit); + numRtpPackets = _rtpCount; + numDroppedPackets = _dropCount; + numRtcpPackets = _rtcpCount; + return; +} + +void tbExternalTransport::EnableSSRCCheck() +{ + CriticalSectionScoped cs(_statCrit); + _checkSSRC = true; +} +unsigned int tbExternalTransport::ReceivedSSRC() +{ + CriticalSectionScoped cs(_statCrit); + return _lastSSRC; +} + +void tbExternalTransport::EnableSequenceNumberCheck() +{ + CriticalSectionScoped cs(_statCrit); + _checkSequenceNumber = true; +} + +unsigned short tbExternalTransport::GetFirstSequenceNumber() +{ + CriticalSectionScoped cs(_statCrit); + return _firstSequenceNumber; +} + +bool tbExternalTransport::ViEExternalTransportRun(void* object) +{ + return static_cast + (object)->ViEExternalTransportProcess(); +} +bool tbExternalTransport::ViEExternalTransportProcess() +{ + unsigned int waitTime = KMaxWaitTimeMs; + + VideoPacket* packet = NULL; + + while (!_rtpPackets.Empty()) + { + // Take first packet in queue + _crit.Enter(); + packet = static_cast ((_rtpPackets.First())->GetItem()); + WebRtc_Word64 timeToReceive = packet->receiveTime - NowMs(); + if (timeToReceive > 0) + { + // No packets to receive yet + if (timeToReceive < waitTime && timeToReceive > 0) + { + waitTime = (unsigned int) timeToReceive; + } + _crit.Leave(); + break; + } + _rtpPackets.PopFront(); + _crit.Leave(); + + // Send to ViE + if (packet) + { + { + CriticalSectionScoped cs(_statCrit); + if (_checkSSRC) + { + _lastSSRC = ((packet->packetBuffer[8]) << 24); + _lastSSRC += (packet->packetBuffer[9] << 16); + _lastSSRC += (packet->packetBuffer[10] << 8); + _lastSSRC += packet->packetBuffer[11]; + _checkSSRC = false; + } + if (_checkSequenceNumber) + { + _firstSequenceNumber + = (unsigned char) packet->packetBuffer[2] << 8; + _firstSequenceNumber + += (unsigned char) packet->packetBuffer[3]; + _checkSequenceNumber = false; + } + } + _vieNetwork.ReceivedRTPPacket(packet->channel, + packet->packetBuffer, packet->length); + delete packet; + packet = NULL; + } + } + while (!_rtcpPackets.Empty()) + { + // Take first packet in queue + _crit.Enter(); + packet = static_cast ((_rtcpPackets.First())->GetItem()); + WebRtc_Word64 timeToReceive = packet->receiveTime - NowMs(); + if (timeToReceive > 0) + { + // No packets to receive yet + if (timeToReceive < waitTime && timeToReceive > 0) + { + waitTime = (unsigned int) timeToReceive; + } + _crit.Leave(); + break; + } + _rtcpPackets.PopFront(); + _crit.Leave(); + + // Send to ViE + if (packet) + { + _vieNetwork.ReceivedRTPPacket(packet->channel, + packet->packetBuffer, packet->length); + delete packet; + packet = NULL; + } + } + _event.Wait(waitTime + 1); // Add 1 ms to not call to early... + return true; +} + +WebRtc_Word64 tbExternalTransport::NowMs() +{ + return TickTime::MillisecondTimestamp(); +} diff --git a/video_engine/main/test/AutoTest/source/tb_interfaces.cc b/video_engine/main/test/AutoTest/source/tb_interfaces.cc new file mode 100644 index 0000000000..3c3483da5e --- /dev/null +++ b/video_engine/main/test/AutoTest/source/tb_interfaces.cc @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "tb_interfaces.h" + +tbInterfaces::tbInterfaces(const char* testName, int& nrOfErrors) : + numberOfErrors(nrOfErrors) +{ + char traceFile[256] = ""; + char traceFileEnc[256] = ""; + +#ifdef ANDROID + strcat(traceFile,"/sdcard/"); +#endif + strcat(traceFile, testName); + strcat(traceFileEnc, traceFile); + strcat(traceFileEnc, "_encrypted"); + + ViETest::Log("Creating ViE Interfaces for test %s\n", testName); + + ptrViE = webrtc::VideoEngine::Create(); + numberOfErrors += ViETest::TestError(ptrViE != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + int error = ptrViE->SetTraceFile(traceFile); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViE->SetTraceFilter(webrtc::kTraceAll); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ptrViEBase = webrtc::ViEBase::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViEBase != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + error = ptrViEBase->Init(); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ptrViECapture = webrtc::ViECapture::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViECapture != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + ptrViERtpRtcp = webrtc::ViERTP_RTCP::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViERtpRtcp != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + ptrViERender = webrtc::ViERender::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViERender != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + ptrViECodec = webrtc::ViECodec::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViECodec != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + ptrViENetwork = webrtc::ViENetwork::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViENetwork != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + ptrViEImageProcess = webrtc::ViEImageProcess::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViEImageProcess != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + ptrViEEncryption = webrtc::ViEEncryption::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViEEncryption != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); +} + +tbInterfaces::~tbInterfaces(void) +{ + int numberOfErrors = 0; + int remainingInterfaces = 0; + + remainingInterfaces = ptrViEEncryption->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViEImageProcess->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViECodec->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViECapture->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViERender->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViERtpRtcp->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViENetwork->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViEBase->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + bool deleted = webrtc::VideoEngine::Delete(ptrViE); + numberOfErrors += ViETest::TestError(deleted == true, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + +} diff --git a/video_engine/main/test/AutoTest/source/tb_video_channel.cc b/video_engine/main/test/AutoTest/source/tb_video_channel.cc new file mode 100644 index 0000000000..8ceb39857a --- /dev/null +++ b/video_engine/main/test/AutoTest/source/tb_video_channel.cc @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "tb_video_channel.h" + +tbVideoChannel::tbVideoChannel(tbInterfaces& Engine, int& nrOfErrors, + webrtc::VideoCodecType sendCodec, int width, + int height, int frameRate, int startBitrate) : + ViE(Engine), numberOfErrors(nrOfErrors), videoChannel(-1) +{ + int error; + error = ViE.ptrViEBase->CreateChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + webrtc::VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + bool sendCodecSet = false; + for (int idx = 0; idx < ViE.ptrViECodec->NumberOfCodecs(); idx++) + { + error = ViE.ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + videoCodec.width = width; + videoCodec.height = height; + videoCodec.maxFramerate = frameRate; + + if (videoCodec.codecType == sendCodec && sendCodecSet == false) + { + if(videoCodec.codecType != webrtc::kVideoCodecI420 ) + { + videoCodec.startBitrate = startBitrate; + videoCodec.maxBitrate = startBitrate * 3; + } + error = ViE.ptrViECodec->SetSendCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + sendCodecSet = true; + } + if (videoCodec.codecType == webrtc::kVideoCodecVP8) + { + videoCodec.width = 352; + videoCodec.height = 288; + } + error = ViE.ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + numberOfErrors += ViETest::TestError(sendCodecSet == true, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + +} + +tbVideoChannel::~tbVideoChannel(void) +{ + int error; + error = ViE.ptrViEBase->DeleteChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +} + +void tbVideoChannel::StartSend(const unsigned short rtpPort /*= 11000*/, + const char* ipAddress /*= "127.0.0.1"*/) +{ + int error; + error = ViE.ptrViENetwork->SetSendDestination(videoChannel, ipAddress, + rtpPort); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +} + +void tbVideoChannel::SetFrameSettings(int width, int height, int frameRate) +{ + int error; + webrtc::VideoCodec videoCodec; + error = ViE.ptrViECodec->GetSendCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + videoCodec.width = width; + videoCodec.height = height; + videoCodec.maxFramerate = frameRate; + + error = ViE.ptrViECodec->SetSendCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + +} +void tbVideoChannel::StopSend() +{ + int error; + error = ViE.ptrViEBase->StopSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +} + +void tbVideoChannel::StartReceive(const unsigned short rtpPort /*= 11000*/) +{ + int error; + + error = ViE.ptrViENetwork->SetLocalReceiver(videoChannel, rtpPort); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +} + +void tbVideoChannel::StopReceive() +{ + int error; + error = ViE.ptrViEBase->StopReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +} + diff --git a/video_engine/main/test/AutoTest/source/vie_autotest.cc b/video_engine/main/test/AutoTest/source/vie_autotest.cc new file mode 100644 index 0000000000..9b966f4cfc --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest.cc @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest.cc +// + + +#include "vie_autotest_defines.h" +#include "vie_autotest.h" + +#include +#include "video_render.h" + +FILE* ViETest::_logFile = NULL; +char* ViETest::_logStr = NULL; + +ViEAutoTest::ViEAutoTest(void* window1, void* window2) : + _window1(window1), + _window2(window2), + _renderType(kRenderDefault), + _vrm1(VideoRender::CreateVideoRender(4561, window1, false, _renderType)), + _vrm2(VideoRender::CreateVideoRender(4562, window2, false, _renderType)) +{ + assert(_vrm1); + assert(_vrm2); + + ViETest::Init(); +} + +ViEAutoTest::~ViEAutoTest() +{ + VideoRender::DestroyVideoRender(_vrm1); + _vrm1 = NULL; + VideoRender::DestroyVideoRender(_vrm2); + _vrm2 = NULL; + + ViETest::Terminate(); +} + +int ViEAutoTest::ViEStandardTest() +{ + int numErrors = 0; + numErrors += ViEBaseStandardTest(); + numErrors += ViECaptureStandardTest(); + numErrors += ViECodecStandardTest(); + numErrors += ViEEncryptionStandardTest(); + numErrors += ViEFileStandardTest(); + numErrors += ViEImageProcessStandardTest(); + numErrors += ViENetworkStandardTest(); + numErrors += ViERenderStandardTest(); + numErrors += ViERtpRtcpStandardTest(); + + if (numErrors > 0) + { + ViETest::Log("Standard Test Failed, with %d erros\n", numErrors); + return numErrors; + } + return numErrors; +} + +int ViEAutoTest::ViEExtendedTest() +{ + int numErrors = 0; + numErrors += ViEBaseExtendedTest(); + numErrors += ViECaptureExtendedTest(); + numErrors += ViECodecExtendedTest(); + numErrors += ViEEncryptionExtendedTest(); + numErrors += ViEFileExtendedTest(); + numErrors += ViEImageProcessExtendedTest(); + numErrors += ViENetworkExtendedTest(); + numErrors += ViERenderExtendedTest(); + numErrors += ViERtpRtcpExtendedTest(); + + if (numErrors > 0) + { + ViETest::Log("Extended Test Failed, with %d erros\n", numErrors); + return numErrors; + } + return numErrors; +} + +int ViEAutoTest::ViEAPITest() +{ + int numErrors = 0; + numErrors += ViEBaseAPITest(); + numErrors += ViECaptureAPITest(); + numErrors += ViECodecAPITest(); + numErrors += ViEEncryptionAPITest(); + numErrors += ViEFileAPITest(); + numErrors += ViEImageProcessAPITest(); + numErrors += ViENetworkAPITest(); + numErrors += ViERenderAPITest(); + numErrors += ViERtpRtcpAPITest(); + + if (numErrors > 0) + { + ViETest::Log("API Test Failed, with %d erros\n", numErrors); + return numErrors; + } + return 0; +} + +void ViEAutoTest::PrintVideoCodec(const webrtc::VideoCodec videoCodec) +{ + using namespace std; + ViETest::Log("Video Codec Information:"); + + switch (videoCodec.codecType) + { + case webrtc::kVideoCodecH263: + ViETest::Log("\tcodecType: H263"); + break; + case webrtc::kVideoCodecVP8: + ViETest::Log("\tcodecType: VP8"); + break; + // TODO(sh): keep or remove MPEG4? + // case webrtc::kVideoCodecMPEG4: + // ViETest::Log("\tcodecType: MPEG4"); + // break; + case webrtc::kVideoCodecI420: + ViETest::Log("\tcodecType: I420"); + break; + case webrtc::kVideoCodecRED: + ViETest::Log("\tcodecType: RED"); + break; + case webrtc::kVideoCodecULPFEC: + ViETest::Log("\tcodecType: ULPFEC"); + break; + case webrtc::kVideoCodecUnknown: + ViETest::Log("\tcodecType: ????"); + break; + default: + ViETest::Log("\tcodecType: ????"); + break; + } + + //cout << "\tcodecSpecific: " << videoCodec.codecSpecific << endl; + //switch(videoCodec.codecSpecific) + //{ + // webrtc::VideoCodecH263 H263; + // webrtc::VideoCodecVP8 VP8; + // webrtc::VideoCodecMPEG4 MPEG4; + // webrtc::VideoCodecGeneric Generic; + //} + + ViETest::Log("\theight: %u", videoCodec.height); + ViETest::Log("\tmaxBitrate: %u", videoCodec.maxBitrate); + ViETest::Log("\tmaxFramerate: %u", videoCodec.maxFramerate); + ViETest::Log("\tminBitrate: %u", videoCodec.minBitrate); + ViETest::Log("\tplName: %s", videoCodec.plName); + ViETest::Log("\tplType: %u", videoCodec.plType); + ViETest::Log("\tstartBitrate: %u", videoCodec.startBitrate); + ViETest::Log("\twidth: %u", videoCodec.width); + ViETest::Log(""); +} + +void ViEAutoTest::PrintAudioCodec(const webrtc::CodecInst audioCodec) +{ + using namespace std; + ViETest::Log("Audio Codec Information:"); + ViETest::Log("\tchannels: %u", audioCodec.channels); + ViETest::Log("\t: %u", audioCodec.pacsize); + ViETest::Log("\t: %u", audioCodec.plfreq); + ViETest::Log("\t: %s", audioCodec.plname); + ViETest::Log("\t: %u", audioCodec.pltype); + ViETest::Log("\t: %u", audioCodec.rate); + ViETest::Log(""); +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_android.cc b/video_engine/main/test/AutoTest/source/vie_autotest_android.cc new file mode 100644 index 0000000000..cd206f4177 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_android.cc @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "../interface/vie_autotest_android.h" + +#include +#include + +#include "vie_autotest.h" +#include "vie_autotest_defines.h" + +int ViEAutoTestAndroid::RunAutotest(int testSelection, int subTestSelection, + void* window1, void* window2, void* javaVM, + void* env, void* context) +{ + ViEAutoTest vieAutoTest(window1, window2); + ViETest::Log("RunAutoTest(%d, %d)", testSelection, subTestSelection); + VideoEngine::SetAndroidObjects(javaVM, context); + VoiceEngine::SetAndroidObjects(javaVM, env, context); + int testErrors = 0; + + if (subTestSelection == 0) + { + // Run all selected test + switch (testSelection) + { + case 0: + testErrors += vieAutoTest.ViEStandardTest(); + if (testErrors == 0) + { + // No errors found in delivery test, create delivery + ViETest::Log("Standard/delivery passed. "); + } + else + { + // Didn't pass + ViETest::Log("\nStandard/delivery test failed."); + } + break; + case 1: + testErrors += vieAutoTest.ViEAPITest(); + break; + case 2: + testErrors += vieAutoTest.ViEExtendedTest(); + break; + case 3: + testErrors += vieAutoTest.ViELoopbackCall(); + break; + default: + break; + } + } + + switch (testSelection) + { + case 0: // Specific standard test + switch (subTestSelection) + { + case 1: // base + testErrors += vieAutoTest.ViEBaseStandardTest(); + break; + + case 2: // capture + testErrors += vieAutoTest.ViECaptureStandardTest(); + break; + + case 3: // codec + testErrors += vieAutoTest.ViECodecStandardTest(); + break; + + case 5: //encryption + testErrors += vieAutoTest.ViEEncryptionStandardTest(); + break; + + case 6: // file + testErrors += vieAutoTest.ViEFileStandardTest(); + break; + + case 7: // image process + testErrors += vieAutoTest.ViEImageProcessStandardTest(); + break; + + case 8: // network + testErrors += vieAutoTest.ViENetworkStandardTest(); + break; + + case 9: // Render + testErrors += vieAutoTest.ViERenderStandardTest(); + break; + + case 10: // RTP/RTCP + testErrors += vieAutoTest.ViERtpRtcpStandardTest(); + break; + + default: + break; + } + break; + + case 1:// specific API + switch (subTestSelection) + { + case 1: // base + testErrors += vieAutoTest.ViEBaseAPITest(); + break; + + case 2: // capture + testErrors += vieAutoTest.ViECaptureAPITest(); + break; + + case 3: // codec + testErrors += vieAutoTest.ViECodecAPITest(); + break; + + case 5: //encryption + testErrors += vieAutoTest.ViEEncryptionAPITest(); + break; + + case 6: // file + testErrors += vieAutoTest.ViEFileAPITest(); + break; + + case 7: // image process + testErrors += vieAutoTest.ViEImageProcessAPITest(); + break; + + case 8: // network + testErrors += vieAutoTest.ViENetworkAPITest(); + break; + + case 9: // Render + testErrors += vieAutoTest.ViERenderAPITest(); + break; + + case 10: // RTP/RTCP + testErrors += vieAutoTest.ViERtpRtcpAPITest(); + break; + case 11: + break; + + default: + break; + } + break; + + case 2:// specific extended + + switch (subTestSelection) + { + case 1: // base + testErrors += vieAutoTest.ViEBaseExtendedTest(); + break; + + case 2: // capture + testErrors += vieAutoTest.ViECaptureExtendedTest(); + break; + + case 3: // codec + testErrors += vieAutoTest.ViECodecExtendedTest(); + break; + + case 5: //encryption + testErrors += vieAutoTest.ViEEncryptionExtendedTest(); + break; + + case 6: // file + testErrors += vieAutoTest.ViEFileExtendedTest(); + break; + + case 7: // image process + testErrors += vieAutoTest.ViEImageProcessExtendedTest(); + break; + + case 8: // network + testErrors += vieAutoTest.ViENetworkExtendedTest(); + break; + + case 9: // Render + testErrors += vieAutoTest.ViERenderExtendedTest(); + break; + + case 10: // RTP/RTCP + testErrors += vieAutoTest.ViERtpRtcpExtendedTest(); + break; + case 11: + break; + + default: + break; + } + break; + case 3: + testErrors += vieAutoTest.ViELoopbackCall(); + break; + default: + break; + } + + if (testErrors) + { + ViETest::Log("Test done with %d errors!\n", testErrors); + } + else + { + ViETest::Log("Test passed!\n"); + } + return testErrors; +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_base.cc b/video_engine/main/test/AutoTest/source/vie_autotest_base.cc new file mode 100644 index 0000000000..81a8a4ea99 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_base.cc @@ -0,0 +1,578 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_base.cc +// + +#include "vie_autotest_defines.h" +#include "vie_autotest.h" +#include "engine_configurations.h" +#include "video_capture.h" + +int ViEAutoTest::ViEBaseStandardTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEBase Standard Test"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + ViETest::Log("Starting a loopback call..."); + + VideoEngine* ptrViE = NULL; + ptrViE = VideoEngine::Create(); + numberOfErrors += ViETest::TestError(ptrViE != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); +#ifdef ANDROID + error = ptrViE->SetTraceFile("/sdcard/ViEBaseStandardTest.txt"); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); +#else + error = ptrViE->SetTraceFile("ViEBaseStandardTest.txt"); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#endif + ViEBase* ptrViEBase = ViEBase::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViEBase != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + error = ptrViEBase->Init(); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + int videoChannel = -1; + error = ptrViEBase->CreateChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViECapture* ptrViECapture = ViECapture::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViECapture != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + VideoCaptureModule* vcpm(NULL); + + const unsigned int KMaxDeviceNameLength = 128; + const unsigned int KMaxUniqueIdLength = 256; + WebRtc_UWord8 deviceName[KMaxDeviceNameLength]; + memset(deviceName, 0, KMaxDeviceNameLength); + WebRtc_UWord8 uniqueId[KMaxUniqueIdLength]; + memset(uniqueId, 0, KMaxUniqueIdLength); + + bool captureDeviceSet = false; + int captureId = 0; + VideoCaptureModule::DeviceInfo* devInfo = + VideoCaptureModule::CreateDeviceInfo(0); + + for (unsigned int captureIdx = 0; + captureIdx < devInfo->NumberOfDevices(); + captureIdx++) + { + error = devInfo->GetDeviceName(captureIdx, deviceName, + KMaxDeviceNameLength, uniqueId, + KMaxUniqueIdLength); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + vcpm = VideoCaptureModule::Create(4571, uniqueId); + numberOfErrors += ViETest::TestError(vcpm != NULL, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViECapture->AllocateCaptureDevice(*vcpm, captureId); + if (error == 0) + { + ViETest::Log("Using capture device: %s, captureId: %d.", + deviceName, captureId); + captureDeviceSet = true; + break; + } + else + { + VideoCaptureModule::Destroy(vcpm); + vcpm = NULL; + } + } + VideoCaptureModule::DestroyDeviceInfo(devInfo); + + numberOfErrors+= ViETest::TestError( + captureDeviceSet, + "ERROR: %s at line %d - Could not set capture device", + __FUNCTION__, __LINE__); + + error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViERTP_RTCP* ptrViERtpRtcp = ViERTP_RTCP::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViE != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + error = ptrViERtpRtcp->SetRTCPStatus(videoChannel, kRtcpCompound_RFC4585); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetKeyFrameRequestMethod(videoChannel, + kViEKeyFrameRequestPliRtcp); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetTMMBRStatus(videoChannel, true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViERender* ptrViERender = ViERender::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViERender != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + error = ptrViERender->RegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->AddRenderer(captureId, _window1, 0, 0.0, 0.0, 1.0, + 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->StartRender(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + + error = ptrViERender->RegisterVideoRenderModule(*_vrm2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->AddRenderer(videoChannel, _window2, 1, 0.0, 0.0, 1.0, + 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->StartRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViECodec* ptrViECodec = ViECodec::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViECodec != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + webrtc::VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + for (int idx = 0; idx < ptrViECodec->NumberOfCodecs(); idx++) + { + error = ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // try to keep the test frame size small when I420 + if (videoCodec.codecType == webrtc::kVideoCodecI420) + { + videoCodec.width = 176; + videoCodec.height = 144; + error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + + error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + + ViENetwork* ptrViENetwork = ViENetwork::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViENetwork != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + char version[1024] = ""; + int versionLength = 1024; + error = ptrViEBase->GetVersion(version); + + ViETest::Log("\nUsing WebRTC Video Engine version: %s", version); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + const char* ipAddress = "127.0.0.1"; + unsigned short rtpPortListen = 6000; + unsigned short rtpPortSend = 6000; + + + rtpPortListen = 6100; + rtpPortSend = 6100; + + error = ptrViENetwork->SetLocalReceiver(videoChannel, rtpPortListen); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->StartReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViENetwork->SetSendDestination(videoChannel, ipAddress, + rtpPortSend); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->StartSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + + error = ptrViERender->MirrorRenderStream(captureId, true, false, true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Call started + ViETest::Log("Call started"); + ViETest::Log("You should see a mirrored local preview from camera %s in " + "window 1 and the remote video in window 2.", + deviceName); + + //*************************************************************** + // Finished initializing engine. Begin testing + //*************************************************************** + + AutoTestSleep(KAutoTestSleepTimeMs); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + // Shut down + error = ptrViEBase->StopReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->StopRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->RemoveRenderer(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->DeRegisterVideoRenderModule(*_vrm2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + int remainingInterfaces = 0; + + error = ptrViEBase->StopSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->RemoveRenderer(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->DeRegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViECapture->StopCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViECapture->DisconnectCaptureDevice(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViECapture->ReleaseCaptureDevice(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + VideoCaptureModule::Destroy(vcpm); + vcpm = NULL; + + remainingInterfaces = ptrViECapture->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + error = ptrViEBase->DeleteChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + remainingInterfaces = ptrViECodec->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViERtpRtcp->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViERender->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViENetwork->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViEBase->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + bool deleted = VideoEngine::Delete(ptrViE); + numberOfErrors += ViETest::TestError(deleted == true, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViEBase Standard Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViEBase Standard Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + +int ViEAutoTest::ViEBaseExtendedTest() +{ + // Start with standard test + ViEBaseAPITest(); + ViEBaseStandardTest(); + + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEBase Extended Test"); + + ViETest::Log(" "); + ViETest::Log(" ViEBase Extended Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + + return 0; +} + +int ViEAutoTest::ViEBaseAPITest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEBase API Test"); + + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + VideoEngine* ptrViE = NULL; + ViEBase* ptrViEBase = NULL; + + // Get the ViEBase API + ptrViEBase = ViEBase::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViEBase == NULL); + + ptrViE = VideoEngine::Create(); + numberOfErrors += ViETest::TestError(ptrViE != NULL, "VideoEngine::Create"); + +#ifdef ANDROID + error = ptrViE->SetTraceFile("/sdcard/WebRTC/ViESampleCodeTrace.txt"); + numberOfErrors += ViETest::TestError(error == 0, "SetTraceFile error"); + + error = ptrViE->SetTraceFile( + "/sdcard/WebRTC/ViESampleCodeTraceEncrypted.txt"); + numberOfErrors += ViETest::TestError(error == 0, "SetTraceFile"); +#else + error = ptrViE->SetTraceFile("WebRTCViESampleCodeTrace.txt"); + numberOfErrors += ViETest::TestError(error == 0, "SetTraceFile error"); +#endif + + ptrViEBase = ViEBase::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViEBase != NULL); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + char version[1024] = ""; + error = ptrViEBase->GetVersion(version); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->LastError(); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Create without init + int videoChannel = -1; + error = ptrViEBase->CreateChannel(videoChannel); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->Init(); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->CreateChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + int videoChannel2 = -1; + error = ptrViEBase->CreateChannel(videoChannel2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(videoChannel != videoChannel2, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + error = ptrViEBase->DeleteChannel(videoChannel2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Channel doesn't exist + error = ptrViEBase->CreateChannel(videoChannel2, videoChannel + 1); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Channel doesn't exist + error = ptrViEBase->CreateChannel(videoChannel2, videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // VoiceEngine + VoiceEngine* ptrVoE = NULL; + VoEBase* ptrVoEBase = NULL; + int audioChannel = -1; + + ptrVoE = VoiceEngine::Create(); + numberOfErrors += ViETest::TestError(ptrVoE != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + ptrVoEBase = VoEBase::GetInterface(ptrVoE); + numberOfErrors += ViETest::TestError(ptrVoEBase != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + error = ptrVoEBase->Init(); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + audioChannel = ptrVoEBase->CreateChannel(); + numberOfErrors += ViETest::TestError(audioChannel != -1, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // Connect before setting VoE + error = ptrViEBase->ConnectAudioChannel(videoChannel, audioChannel); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->SetVoiceEngine(ptrVoE); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->ConnectAudioChannel(videoChannel, audioChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + error = ptrViEBase->DisconnectAudioChannel(videoChannel + 5); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->DisconnectAudioChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->SetVoiceEngine(NULL); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViEBase* ptrViEBase2 = ViEBase::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViEBase != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + int remainingInterfaces = ptrViEBase->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 1, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + bool vieDeleted = VideoEngine::Delete(ptrViE); + numberOfErrors += ViETest::TestError(vieDeleted == false, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViEBase->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + vieDeleted = VideoEngine::Delete(ptrViE); + numberOfErrors += ViETest::TestError(vieDeleted == true, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + if (numberOfErrors > 0) + { + ViETest::Log(" "); + ViETest::Log(" ERROR ViEBase API Test FAILED! "); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViEBase API Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + + return 0; +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_capture.cc b/video_engine/main/test/AutoTest/source/vie_autotest_capture.cc new file mode 100644 index 0000000000..c5054ab24c --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_capture.cc @@ -0,0 +1,808 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_autotest_capture.cc + */ + +#include "vie_autotest_defines.h" +#include "vie_autotest.h" +#include "engine_configurations.h" + +#include "common_types.h" +#include "voe_base.h" +#include "vie_base.h" +#include "vie_capture.h" +#include "vie_codec.h" +#include "vie_network.h" +#include "vie_render.h" +#include "vie_rtp_rtcp.h" +#include "tick_util.h" + +#include "tb_interfaces.h" +#include "tb_video_channel.h" +#include "video_capture.h" + +class CaptureObserver: public ViECaptureObserver +{ +public: + CaptureObserver() : + _brightness(Normal), _alarm(AlarmCleared), _frameRate(0) + {} + + virtual void BrightnessAlarm(const int captureId, + const Brightness brightness) + { + _brightness = brightness; + switch (brightness) + { + case Normal: + ViETest::Log(" BrightnessAlarm Normal"); + break; + case Bright: + ViETest::Log(" BrightnessAlarm Bright"); + break; + case Dark: + ViETest::Log(" BrightnessAlarm Dark"); + break; + default: + assert(!"Unknown brightness alarm"); + } + } + + virtual void CapturedFrameRate(const int captureId, + const unsigned char frameRate) + { + ViETest::Log(" CapturedFrameRate %u", frameRate); + _frameRate = frameRate; + } + + virtual void NoPictureAlarm(const int captureId, const CaptureAlarm alarm) + { + _alarm = alarm; + if (alarm == AlarmRaised) + { + ViETest::Log("NoPictureAlarm CARaised."); + } + else + { + ViETest::Log("NoPictureAlarm CACleared."); + } + } + + Brightness _brightness; + CaptureAlarm _alarm; + unsigned char _frameRate; +}; + +class CaptureEffectFilter: public ViEEffectFilter +{ +public: + CaptureEffectFilter(int reqWidth, int reqHeight, int& numberOfErrors) : + _numberOfCapturedFrames(0), + _reqWidth(reqWidth), + _reqHeight(reqHeight), + _numberOfErrors(numberOfErrors) + { + } + // Implements ViEEffectFilter + virtual int Transform(int size, unsigned char* frameBuffer, + unsigned int timeStamp90KHz, unsigned int width, + unsigned int height) + { + _numberOfErrors += ViETest::TestError( + frameBuffer != 0 + && width == _reqWidth + && height == _reqHeight, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + ++_numberOfCapturedFrames; + return 0; + } + + int _numberOfCapturedFrames; + +protected: + int _reqWidth; + int _reqHeight; + int& _numberOfErrors; +}; + +int ViEAutoTest::ViECaptureStandardTest() +{ + int numberOfErrors = 0; + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViECapture StandardTest Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + + int error = 0; + tbInterfaces ViE("WebRTCViECapture_Standard", numberOfErrors); + + VideoCaptureModule::DeviceInfo* devInfo = + VideoCaptureModule::CreateDeviceInfo(0); + + int numberOfCaptureDevices = devInfo->NumberOfDevices(); + ViETest::Log("Number of capture devices %d", numberOfCaptureDevices); + numberOfErrors += ViETest::TestError(numberOfCaptureDevices > 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + int captureDeviceId[10]; + VideoCaptureModule* vcpms[10]; + memset(vcpms, 0, sizeof(vcpms)); + + //Check capabilities + for (int deviceIndex = 0; + deviceIndex < numberOfCaptureDevices; + ++deviceIndex) + { + WebRtc_UWord8 deviceName[128]; + WebRtc_UWord8 deviceUniqueName[512]; + + error = devInfo->GetDeviceName(deviceIndex, deviceName, + sizeof(deviceName), deviceUniqueName, + sizeof(deviceUniqueName)); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("Found capture device %s\nUnique name %s", deviceName, + deviceUniqueName); + +// not supported on MAC (is part of capture capabilites +#if !defined(WEBRTC_LINUX) && !defined(WEBRTC_MAC_INTEL) + error = ViE.ptrViECapture->ShowCaptureSettingsDialogBox( + (char*) deviceUniqueName, + (unsigned int) (strlen((char*) deviceUniqueName)), + "WebRTCViECapture StandardTest"); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#endif + +#if !defined(WEBRTC_MAC_INTEL) // these functions will return -1 + unsigned int numberOfCapabilities = + devInfo->NumberOfCapabilities(deviceUniqueName); + numberOfErrors += ViETest::TestError(numberOfCapabilities > 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + for (unsigned int capIndex = 0; + capIndex < numberOfCapabilities; + ++capIndex) + { + VideoCaptureCapability capability; + error = devInfo->GetCapability(deviceUniqueName, capIndex, + capability); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("Capture capability %d (of %u)", capIndex + 1, + numberOfCapabilities); + ViETest::Log("witdh %d, height %d, frame rate %d", + capability.width, capability.height, capability.maxFPS); + ViETest::Log("expected delay %d, color type %d, encoding %d", + capability.expectedCaptureDelay, capability.rawType, + capability.codecType); + numberOfErrors += ViETest::TestError( + capability.width > 0 + && capability.height > 0 + && capability.maxFPS >= 0 + && capability.expectedCaptureDelay > 0, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + } +#endif + } +#if !defined(WEBRTC_MAC_INTEL) + // "capture capability functios" are not supported on WEBRTC_MAC_INTEL + //Check allocation. Try to allocate them all after each other. + + for (int deviceIndex = 0; + deviceIndex < numberOfCaptureDevices; + ++deviceIndex) + { + WebRtc_UWord8 deviceName[128]; + WebRtc_UWord8 deviceUniqueName[512]; + + error = devInfo->GetDeviceName(deviceIndex, deviceName, + sizeof(deviceName), deviceUniqueName, + sizeof(deviceUniqueName)); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + VideoCaptureModule* vcpm = VideoCaptureModule::Create(deviceIndex, + deviceUniqueName); + numberOfErrors += ViETest::TestError(vcpm != NULL, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + vcpms[deviceIndex] = vcpm; + + error = ViE.ptrViECapture->AllocateCaptureDevice( + *vcpm, captureDeviceId[deviceIndex]); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + VideoCaptureCapability capability; + error = devInfo->GetCapability(deviceUniqueName, 0, capability); + + // Test that the camera select the closest capability to the selected + // widht and height. + CaptureEffectFilter filter(capability.width, capability.height, + numberOfErrors); + error = ViE.ptrViEImageProcess->RegisterCaptureEffectFilter( + captureDeviceId[deviceIndex], filter); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Testing Device %s capability width %d height %d", + deviceUniqueName, capability.width, capability.height); + capability.height = capability.height - 2; + capability.width = capability.width - 2; + + CaptureCapability vieCapability; + vieCapability.width = capability.width; + vieCapability.height = capability.height; + vieCapability.codecType = capability.codecType; + vieCapability.maxFPS = capability.maxFPS; + vieCapability.rawType = capability.rawType; + + error = ViE.ptrViECapture->StartCapture(captureDeviceId[deviceIndex], + vieCapability); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + TickTime startTime = TickTime::Now(); + + while (filter._numberOfCapturedFrames < 10 + && (TickTime::Now() - startTime).Milliseconds() < 10000) + { + AutoTestSleep(100); + } + numberOfErrors += ViETest::TestError(filter._numberOfCapturedFrames + >= 10, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->DeregisterCaptureEffectFilter( + captureDeviceId[deviceIndex]); + +#ifdef ANDROID // Can only allocate one camera at the time on Android + error = ViE.ptrViECapture->StopCapture(captureDeviceId[deviceIndex]); + numberOfErrors += ViETest::TestError(error==0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViECapture->ReleaseCaptureDevice( + captureDeviceId[deviceIndex]); + numberOfErrors += ViETest::TestError(error==0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#endif + } + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + + // stop all started capture devices + for (int deviceIndex = 0; deviceIndex < numberOfCaptureDevices; ++deviceIndex) + { + error = ViE.ptrViECapture->StopCapture(captureDeviceId[deviceIndex]); +#ifdef ANDROID + // Camera already stoped on Android since we can only allocate one + // camera at the time. + numberOfErrors += ViETest::TestError(error==-1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#else + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#endif + + error = ViE.ptrViECapture->ReleaseCaptureDevice( + captureDeviceId[deviceIndex]); +#ifdef ANDROID + // Camera already stoped on Android since we can only allocate one + // camera at the time + numberOfErrors += ViETest::TestError(error==-1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#else + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#endif + VideoCaptureModule::Destroy(vcpms[deviceIndex]); + } +#endif + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViECapture Standard Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + VideoCaptureModule::DestroyDeviceInfo(devInfo); + + ViETest::Log(" "); + ViETest::Log(" ViECapture Standard Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + + return 0; +} + +int ViEAutoTest::ViECaptureExtendedTest() +{ + + // Test + int numberOfErrors = 0; + numberOfErrors += ViECaptureStandardTest(); + numberOfErrors += ViECaptureAPITest(); + numberOfErrors += ViECaptureExternalCaptureTest(); + + return 0; +} + +int ViEAutoTest::ViECaptureAPITest() +{ + int numberOfErrors = 0; + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViECapture API Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + int error = 0; + tbInterfaces ViE("WebRTCViECapture_API", numberOfErrors); + + ViE.ptrViECapture->NumberOfCaptureDevices(); + + WebRtc_UWord8 deviceName[128]; + WebRtc_UWord8 deviceUniqueName[512]; + int captureId = 0; + int dummy = 0; + + VideoCaptureModule::DeviceInfo* devInfo = + VideoCaptureModule::CreateDeviceInfo(0); + numberOfErrors += ViETest::TestError(devInfo != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // Get the first capture device + error = devInfo->GetDeviceName(0, deviceName, sizeof(deviceName), + deviceUniqueName, sizeof(deviceUniqueName)); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + VideoCaptureModule* vcpm = VideoCaptureModule::Create(0, deviceUniqueName); + numberOfErrors += ViETest::TestError(vcpm != NULL, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Allocate capture device + error = ViE.ptrViECapture->AllocateCaptureDevice(*vcpm, captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Start the capture device + error = ViE.ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Start again. Should fail + error = ViE.ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(ViE.LastError() + == kViECaptureDeviceAlreadyStarted, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Start invalid capture device + error = ViE.ptrViECapture->StartCapture(captureId + 1); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(ViE.LastError() + == kViECaptureDeviceDoesnNotExist, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Stop invalide capture device + error = ViE.ptrViECapture->StopCapture(captureId + 1); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(ViE.LastError() + == kViECaptureDeviceDoesnNotExist, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Stop the capture device + error = ViE.ptrViECapture->StopCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Stop the capture device again + error = ViE.ptrViECapture->StopCapture(captureId); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(ViE.LastError() + == kViECaptureDeviceNotStarted, "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // Connect to invalid channel + error = ViE.ptrViECapture->ConnectCaptureDevice(captureId, 0); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(ViE.LastError() + == kViECaptureDeviceInvalidChannelId, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + tbVideoChannel channel(ViE, numberOfErrors); + + // Connect invalid captureId + error = ViE.ptrViECapture->ConnectCaptureDevice(captureId + 1, + channel.videoChannel); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(ViE.LastError() + == kViECaptureDeviceDoesnNotExist, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // Connect the capture device to the channel + error = ViE.ptrViECapture->ConnectCaptureDevice(captureId, + channel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Connect the channel again + error = ViE.ptrViECapture->ConnectCaptureDevice(captureId, + channel.videoChannel); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(ViE.LastError() + == kViECaptureDeviceAlreadyConnected, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Start the capture device + error = ViE.ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Release invalid capture device + error = ViE.ptrViECapture->ReleaseCaptureDevice(captureId + 1); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(ViE.LastError() + == kViECaptureDeviceDoesnNotExist, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Release the capture device + error = ViE.ptrViECapture->ReleaseCaptureDevice(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Release the capture device again + error = ViE.ptrViECapture->ReleaseCaptureDevice(captureId); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(ViE.LastError() + == kViECaptureDeviceDoesnNotExist, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Test GetOrientation + VideoCaptureRotation orientation; + WebRtc_UWord8 dummy_name[5]; + error = devInfo->GetOrientation(dummy_name, orientation); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //Test SetRotation + error = ViE.ptrViECapture->SetRotateCapturedFrames(captureId, + RotateCapturedFrame_90); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(ViE.LastError() + == kViECaptureDeviceDoesnNotExist, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Allocate capture device + error = ViE.ptrViECapture->AllocateCaptureDevice(*vcpm, captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViECapture->SetRotateCapturedFrames(captureId, + RotateCapturedFrame_0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViECapture->SetRotateCapturedFrames(captureId, + RotateCapturedFrame_90); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViECapture->SetRotateCapturedFrames(captureId, + RotateCapturedFrame_180); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViECapture->SetRotateCapturedFrames(captureId, + RotateCapturedFrame_270); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Release the capture device + error = ViE.ptrViECapture->ReleaseCaptureDevice(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + VideoCaptureModule::DestroyDeviceInfo(devInfo); + VideoCaptureModule::Destroy(vcpm); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR WebRTCViECapture API Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" WebRTCViECapture API Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + + return numberOfErrors; +} + +int ViEAutoTest::ViECaptureExternalCaptureTest() +{ + int numberOfErrors = 0; + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" WebRTCViECapture External Capture Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + int error = 0; + tbInterfaces ViE("WebRTCViECapture_ExternalCapture", numberOfErrors); + tbVideoChannel channel(ViE, numberOfErrors); + channel.StartReceive(); + channel.StartSend(); + + VideoCaptureExternal* externalCapture; + int captureId = 0; + + // Allocate the external capture device + VideoCaptureModule* vcpm = VideoCaptureModule::Create(0, externalCapture); + numberOfErrors += ViETest::TestError(vcpm != NULL, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViECapture->AllocateCaptureDevice(*vcpm, captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(externalCapture != 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // Connect the capture device to the channel + error = ViE.ptrViECapture->ConnectCaptureDevice(captureId, + channel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Render the local capture + error = ViE.ptrViERender->AddRenderer(captureId, _window1, 1, 0.0, 0.0, + 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Render the remote capture + error = ViE.ptrViERender->AddRenderer(channel.videoChannel, _window2, 1, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->StartRender(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->StartRender(channel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Register observer + CaptureObserver observer; + error = ViE.ptrViECapture->RegisterObserver(captureId, observer); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Enable brighness alarm + error = ViE.ptrViECapture->EnableBrightnessAlarm(captureId, true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + CaptureEffectFilter effectFilter(176, 144, numberOfErrors); + error = ViE.ptrViEImageProcess->RegisterCaptureEffectFilter(captureId, + effectFilter); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Call started + + ViETest::Log("You should see local preview from external capture\n" + "in window 1 and the remote video in window 2.\n"); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + const unsigned int videoFrameLength = (176 * 144 * 3) / 2; + unsigned char* videoFrame = new unsigned char[videoFrameLength]; + memset(videoFrame, 128, 176 * 144); + + // TODO: Find a file to use for testing. + // FILE* foreman = OpenTestFile("akiyo_qcif.yuv"); + // if (foreman == NULL) + // { + // ViETest::Log("Failed to open file akiyo_qcif.yuv"); + // } + + int frameCount = 0; + VideoCaptureCapability capability; + capability.width = 176; + capability.height = 144; + capability.rawType = kVideoI420; + + ViETest::Log("Testing external capturing and frame rate callbacks."); + // TODO: Change when using a real file! + // while (fread(videoFrame, videoFrameLength, 1, foreman) == 1) + while (frameCount < 120) + { + + externalCapture->IncomingFrame( + videoFrame, videoFrameLength, capability, + TickTime::Now().MillisecondTimestamp()); + AutoTestSleep(33); + + if (effectFilter._numberOfCapturedFrames > 2) + { + // make sure brigthness or no picture alarm has not been triggered + numberOfErrors += ViETest::TestError(observer._brightness == Normal, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError( + observer._alarm == AlarmCleared, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + frameCount++; + } + + // Test brightness alarm + // Test bright image + for (int i = 0; i < 176 * 144; ++i) + { + if (videoFrame[i] <= 155) + videoFrame[i] = videoFrame[i] + 100; + else + videoFrame[i] = 255; + } + ViETest::Log("Testing Brighness alarm"); + for (int frame = 0; frame < 30; ++frame) + { + externalCapture->IncomingFrame( + videoFrame, videoFrameLength, capability, + TickTime::Now().MillisecondTimestamp()); + AutoTestSleep(33); + } + numberOfErrors += ViETest::TestError(observer._brightness == Bright, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // Test Dark image + for (int i = 0; i < 176 * 144; ++i) + { + videoFrame[i] = videoFrame[i] > 200 ? videoFrame[i] - 200 : 0; + } + for (int frame = 0; frame < 30; ++frame) + { + externalCapture->IncomingFrame( + videoFrame, videoFrameLength, capability, + TickTime::Now().MillisecondTimestamp()); + AutoTestSleep(33); + } + numberOfErrors += ViETest::TestError(observer._brightness == Dark, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // Test that frames were played + numberOfErrors += ViETest::TestError( + effectFilter._numberOfCapturedFrames > 150, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + // Test frame rate callback + numberOfErrors += ViETest::TestError(observer._frameRate >= 29 + && observer._frameRate <= 30, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // Test no picture alarm + ViETest::Log("Testing NoPictureAlarm."); + AutoTestSleep(1050); + numberOfErrors += ViETest::TestError(observer._alarm == AlarmRaised, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + for (int frame = 0; frame < 10; ++frame) + { + externalCapture->IncomingFrame( + videoFrame, videoFrameLength, capability, + TickTime::Now().MillisecondTimestamp()); + AutoTestSleep(33); + } + numberOfErrors += ViETest::TestError(observer._alarm == AlarmCleared, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + delete videoFrame; + + // Release the capture device + error = ViE.ptrViECapture->ReleaseCaptureDevice(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Release the capture device again + error = ViE.ptrViECapture->ReleaseCaptureDevice(captureId); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError( + ViE.LastError() == kViECaptureDeviceDoesnNotExist, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR WebRTCViECapture External Capture Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" WebRTCViECapture External Capture Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + + return numberOfErrors; +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_codec.cc b/video_engine/main/test/AutoTest/source/vie_autotest_codec.cc new file mode 100644 index 0000000000..9bbbfd2ea9 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_codec.cc @@ -0,0 +1,1298 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_codec.cc +// + +#include "vie_autotest_defines.h" +#include "vie_autotest.h" +#include "engine_configurations.h" + +#include "common_types.h" +#include "tb_capture_device.h" +#include "tb_I420_codec.h" +#include "tb_interfaces.h" +#include "tb_video_channel.h" +#include "vie_base.h" +#include "vie_capture.h" +#include "vie_codec.h" +#include "vie_network.h" +#include "vie_render.h" +#include "vie_rtp_rtcp.h" +#include "voe_base.h" + +class ViEAutotestCodecObserever: public ViEEncoderObserver, + public ViEDecoderObserver +{ +public: + int incomingCodecCalled; + int incomingRatecalled; + int outgoingRatecalled; + + unsigned char lastPayloadType; + unsigned short lastWidth; + unsigned short lastHeight; + + unsigned int lastOutgoingFramerate; + unsigned int lastOutgoingBitrate; + unsigned int lastIncomingFramerate; + unsigned int lastIncomingBitrate; + + webrtc::VideoCodec incomingCodec; + + ViEAutotestCodecObserever() + { + incomingCodecCalled = 0; + incomingRatecalled = 0; + outgoingRatecalled = 0; + lastPayloadType = 0; + lastWidth = 0; + lastHeight = 0; + lastOutgoingFramerate = 0; + lastOutgoingBitrate = 0; + lastIncomingFramerate = 0; + lastIncomingBitrate = 0; + memset(&incomingCodec, 0, sizeof(incomingCodec)); + } + virtual void IncomingCodecChanged(const int videoChannel, + const webrtc::VideoCodec& videoCodec) + { + incomingCodecCalled++; + lastPayloadType = videoCodec.plType; + lastWidth = videoCodec.width; + lastHeight = videoCodec.height; + + memcpy(&incomingCodec, &videoCodec, sizeof(videoCodec)); + } + + virtual void IncomingRate(const int videoChannel, + const unsigned int framerate, + const unsigned int bitrate) + { + incomingRatecalled++; + lastIncomingFramerate += framerate; + lastIncomingBitrate += bitrate; + } + + virtual void OutgoingRate(const int videoChannel, + const unsigned int framerate, + const unsigned int bitrate) + { + outgoingRatecalled++; + lastOutgoingFramerate += framerate; + lastOutgoingBitrate += bitrate; + } + + virtual void RequestNewKeyFrame(const int videoChannel) + { + } +}; + +class ViEAutoTestEffectFilter: public ViEEffectFilter +{ +public: + int numFrames; + ViEAutoTestEffectFilter() + { + numFrames = 0; + } + ~ViEAutoTestEffectFilter() + { + } + + virtual int Transform(int size, unsigned char* frameBuffer, + unsigned int timeStamp90KHz, unsigned int width, + unsigned int height) + { + numFrames++; + return 0; + } +}; + +int ViEAutoTest::ViECodecStandardTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViECodec Standard Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + tbInterfaces interfaces = tbInterfaces("ViECodecStandardTest", + numberOfErrors); + + tbCaptureDevice captureDevice = tbCaptureDevice(interfaces, numberOfErrors); + int captureId = captureDevice.captureId; + + VideoEngine* ptrViE = interfaces.ptrViE; + ViEBase* ptrViEBase = interfaces.ptrViEBase; + ViECapture* ptrViECapture = interfaces.ptrViECapture; + ViERender* ptrViERender = interfaces.ptrViERender; + ViECodec* ptrViECodec = interfaces.ptrViECodec; + ViERTP_RTCP* ptrViERtpRtcp = interfaces.ptrViERtpRtcp; + ViENetwork* ptrViENetwork = interfaces.ptrViENetwork; + + int videoChannel = -1; + error = ptrViEBase->CreateChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetRTCPStatus(videoChannel, kRtcpCompound_RFC4585); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetKeyFrameRequestMethod(videoChannel, + kViEKeyFrameRequestPliRtcp); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetTMMBRStatus(videoChannel, true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->AddRenderer(captureId, _window1, 0, 0.0, 0.0, 1.0, + 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->AddRenderer(videoChannel, _window2, 1, 0.0, 0.0, 1.0, + 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->StartRender(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->StartRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + + webrtc::VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + for (int idx = 0; idx < ptrViECodec->NumberOfCodecs(); idx++) + { + error = ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + if (videoCodec.codecType != webrtc::kVideoCodecH263 + && videoCodec.codecType != webrtc::kVideoCodecI420) + { + videoCodec.width = 640; + videoCodec.height = 480; + } + if(videoCodec.codecType==kVideoCodecI420) + { + videoCodec.width=176; + videoCodec.height=144; + } + error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + + for (int idx = 0; idx < ptrViECodec->NumberOfCodecs(); idx++) + { + error = ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + if (videoCodec.codecType == webrtc::kVideoCodecVP8) + { + error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + break; + } + } + + const char* ipAddress = "127.0.0.1"; + const unsigned short rtpPort = 6000; + error = ptrViENetwork->SetLocalReceiver(videoChannel, rtpPort); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->StartReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViENetwork->SetSendDestination(videoChannel, ipAddress, rtpPort); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->StartSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // Make sure all codecs runs + // + { + ViEImageProcess* ptrViEImageProcess = ViEImageProcess::GetInterface(ptrViE); + ViEAutotestCodecObserever codecObserver; + error = ptrViECodec->RegisterDecoderObserver(videoChannel, + codecObserver); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Loop through all codecs for %d seconds", + KAutoTestSleepTimeMs / 1000); + for (int idx = 0; idx < ptrViECodec->NumberOfCodecs() - 2; idx++) + { + error = ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + if (videoCodec.codecType != webrtc::kVideoCodecMPEG4) + { + if(videoCodec.codecType==kVideoCodecI420) // Lower resolution to sockkets keep up. + { + videoCodec.width=176; + videoCodec.height=144; + videoCodec.maxFramerate=15; + } + error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("\t %d. %s", idx, videoCodec.plName); + + ViEAutoTestEffectFilter frameCounter; + error = ptrViEImageProcess->RegisterRenderEffectFilter( + videoChannel, + frameCounter); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + AutoTestSleep( KAutoTestSleepTimeMs); + + // Verify we've received and decoded correct payload + numberOfErrors += ViETest::TestError( + codecObserver.incomingCodec.codecType + == videoCodec.codecType, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + int maxNumberOfRenderedFrames = videoCodec.maxFramerate + * KAutoTestSleepTimeMs / 1000; + + if(videoCodec.codecType==kVideoCodecI420) + { + // Due to that I420 needs a huge bandwidht- rate control can set frame rate very low. + // This happen since we use the same channel as we just tested with vp8. + numberOfErrors += ViETest::TestError(frameCounter.numFrames>0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + } + else + { + +#ifdef ANDROID + // To get the autotest to pass on some slow devices + numberOfErrors += ViETest::TestError(frameCounter.numFrames + > maxNumberOfRenderedFrames/6, // Safety margin due to bitrate + "ERROR: %s at line %d", __FUNCTION__, __LINE__); +#else + numberOfErrors += ViETest::TestError(frameCounter.numFrames + > maxNumberOfRenderedFrames / 4, // Safety margin due to bitrate + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); +#endif + } + + error = ptrViEImageProcess->DeregisterRenderEffectFilter( + videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + else + { + ViETest::Log("\t %d. %s not tested", idx, videoCodec.plName); + } + } + ptrViEImageProcess->Release(); + error = ptrViECodec->DeregisterDecoderObserver(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("Done!"); + } + + // + // Callbacks + // + + ViEAutotestCodecObserever codecObserver; + error = ptrViECodec->RegisterEncoderObserver(videoChannel, codecObserver); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ptrViECodec->RegisterDecoderObserver(videoChannel, codecObserver); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("\nTesting codec callbacks..."); + + for (int idx = 0; idx < ptrViECodec->NumberOfCodecs(); idx++) + { + error = ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + if (videoCodec.codecType == webrtc::kVideoCodecVP8) + { + error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + break; + } + } + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ptrViEBase->StopSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViECodec->DeregisterEncoderObserver(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ptrViECodec->DeregisterDecoderObserver(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + numberOfErrors += ViETest::TestError(codecObserver.incomingCodecCalled > 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + numberOfErrors += ViETest::TestError(codecObserver.incomingRatecalled > 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + numberOfErrors += ViETest::TestError(codecObserver.outgoingRatecalled > 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + error = ptrViEBase->StopReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->StopSend(videoChannel); // Already stopped + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->StopRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->RemoveRenderer(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->RemoveRenderer(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViECapture->DisconnectCaptureDevice(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->DeleteChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + + + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViECodec Standard Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViECodec Standard Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + +int ViEAutoTest::ViECodecExtendedTest() +{ + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + { + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViECodec Extended Test\n"); + + numberOfErrors = ViECodecAPITest(); + numberOfErrors += ViECodecStandardTest(); + numberOfErrors += ViECodecExternalCodecTest(); + + tbInterfaces interfaces = tbInterfaces("ViECodecExtendedTest", + numberOfErrors); + VideoEngine* ptrViE = interfaces.ptrViE; + ViEBase* ptrViEBase = interfaces.ptrViEBase; + ViECapture* ptrViECapture = interfaces.ptrViECapture; + ViERender* ptrViERender = interfaces.ptrViERender; + ViECodec* ptrViECodec = interfaces.ptrViECodec; + ViERTP_RTCP* ptrViERtpRtcp = interfaces.ptrViERtpRtcp; + ViENetwork* ptrViENetwork = interfaces.ptrViENetwork; + + tbCaptureDevice captureDevice = tbCaptureDevice(interfaces, + numberOfErrors); + int captureId = captureDevice.captureId; + + int videoChannel = -1; + error = ptrViEBase->CreateChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetRTCPStatus(videoChannel, + kRtcpCompound_RFC4585); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error + = ptrViERtpRtcp->SetKeyFrameRequestMethod(videoChannel, + kViEKeyFrameRequestPliRtcp); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetTMMBRStatus(videoChannel, true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->AddRenderer(captureId, _window1, 0, 0.0, 0.0, + 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->AddRenderer(videoChannel, _window2, 1, 0.0, 0.0, + 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->StartRender(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->StartRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + webrtc::VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + for (int idx = 0; idx < ptrViECodec->NumberOfCodecs(); idx++) + { + error = ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + if (videoCodec.codecType != webrtc::kVideoCodecH263 + && videoCodec.codecType != webrtc::kVideoCodecI420) + { + videoCodec.width = 640; + videoCodec.height = 480; + } + error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + + const char* ipAddress = "127.0.0.1"; + const unsigned short rtpPort = 6000; + error = ptrViENetwork->SetLocalReceiver(videoChannel, rtpPort); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->StartReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViENetwork->SetSendDestination(videoChannel, ipAddress, + rtpPort); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->StartSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // Codec specific tests + // + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + error = ptrViEBase->StopSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViEAutotestCodecObserever codecObserver; + error = ptrViECodec->RegisterEncoderObserver(videoChannel, + codecObserver); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ptrViECodec->RegisterDecoderObserver(videoChannel, + codecObserver); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + error = ptrViEBase->StopReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->StopSend(videoChannel); // Already stopped + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->StopRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->RemoveRenderer(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViERender->RemoveRenderer(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViECapture->DisconnectCaptureDevice(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEBase->DeleteChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + + // + // Default channel + // + { + // Create VIE + tbInterfaces ViE("ViECodecExtendedTest2", numberOfErrors); + // Create a capture device + tbCaptureDevice tbCapture(ViE, numberOfErrors); + + // Create channel 1 + int videoChannel1 = -1; + error = ViE.ptrViEBase->CreateChannel(videoChannel1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + unsigned short rtpPort1 = 12000; + error = ViE.ptrViENetwork->SetLocalReceiver(videoChannel1, rtpPort1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendDestination(videoChannel1, + "127.0.0.1", rtpPort1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + tbCapture.ConnectTo(videoChannel1); + + error + = ViE.ptrViERtpRtcp->SetKeyFrameRequestMethod( + videoChannel1, kViEKeyFrameRequestPliRtcp); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->AddRenderer(videoChannel1, _window1, 0, 0.0, + 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(videoChannel1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViEAutotestCodecObserever codecObserver1; + error = ViE.ptrViECodec->RegisterEncoderObserver(videoChannel1, + codecObserver1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViECodec->RegisterDecoderObserver(videoChannel1, + codecObserver1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Set Send codec + unsigned short codecWidth = 176; + unsigned short codecHeight = 144; + bool codecSet = false; + webrtc::VideoCodec videoCodec; + for (int idx = 0; idx < ViE.ptrViECodec->NumberOfCodecs(); idx++) + { + error = ViE.ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViECodec->SetReceiveCodec(videoChannel1, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + if (videoCodec.codecType == webrtc::kVideoCodecVP8) + { + videoCodec.width = codecWidth; + videoCodec.height = codecHeight; + videoCodec.startBitrate = 200; + videoCodec.maxBitrate = 300; + error + = ViE.ptrViECodec->SetSendCodec(videoChannel1, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + codecSet = true; + break; + } + } + numberOfErrors += ViETest::TestError(codecSet, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartSend(videoChannel1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartReceive(videoChannel1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Create channel 2, based on channel 1 + int videoChannel2 = -1; + error = ViE.ptrViEBase->CreateChannel(videoChannel2, videoChannel1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(videoChannel1 != videoChannel2, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERtpRtcp->SetKeyFrameRequestMethod( + videoChannel2, kViEKeyFrameRequestPliRtcp); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Prepare receive codecs + for (int idx = 0; idx < ViE.ptrViECodec->NumberOfCodecs(); idx++) + { + error = ViE.ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViECodec->SetReceiveCodec(videoChannel2, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + + ViEAutotestCodecObserever codecObserver2; + error = ViE.ptrViECodec->RegisterDecoderObserver(videoChannel2, + codecObserver2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->AddRenderer(videoChannel2, _window2, 0, 0.0, + 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(videoChannel2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + unsigned short rtpPort2 = 13000; + error = ViE.ptrViENetwork->SetLocalReceiver(videoChannel2, rtpPort2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendDestination(videoChannel2, + "127.0.0.1", rtpPort2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartReceive(videoChannel2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartSend(videoChannel2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("\nTest using one encoder on several channels"); + ViETest::Log( + "Channel 1 is rendered in Window1, channel 2 in Window 2." + "\nSending VP8 on both channels"); + + AutoTestSleep(KAutoTestSleepTimeMs); + + // Check that we received H.263 on both channels + numberOfErrors += ViETest::TestError( + codecObserver1.incomingCodec.codecType == webrtc::kVideoCodecVP8 + && codecObserver1.incomingCodec.width == 176, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError( + codecObserver2.incomingCodec.codecType == + webrtc::kVideoCodecVP8 + && codecObserver2.incomingCodec.width == 176, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + // Delete the first channel and keep the second + error = ViE.ptrViEBase->DeleteChannel(videoChannel1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Channel 1 deleted, you should only see video in Window " + "2"); + + AutoTestSleep(KAutoTestSleepTimeMs); + + // Create another channel + int videoChannel3 = -1; + error = ViE.ptrViEBase->CreateChannel(videoChannel3, videoChannel2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(videoChannel3 != videoChannel2, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERtpRtcp->SetKeyFrameRequestMethod( + videoChannel3, kViEKeyFrameRequestPliRtcp); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Prepare receive codecs + for (int idx = 0; idx < ViE.ptrViECodec->NumberOfCodecs(); idx++) + { + error = ViE.ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViECodec->SetReceiveCodec(videoChannel3, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + + ViEAutotestCodecObserever codecObserver3; + error = ViE.ptrViECodec->RegisterDecoderObserver(videoChannel3, + codecObserver3); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->AddRenderer(videoChannel3, _window1, 0, 0.0, + 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(videoChannel3); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + unsigned short rtpPort3 = 14000; + error = ViE.ptrViENetwork->SetLocalReceiver(videoChannel3, rtpPort3); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendDestination(videoChannel3, + "127.0.0.1", rtpPort3); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartReceive(videoChannel3); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartSend(videoChannel3); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->DeleteChannel(videoChannel2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("A third channel created and rendered in Window 1,\n" + "channel 2 is deleted and you should only see video in Window 1"); + + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViEBase->DeleteChannel(videoChannel3); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + + // SetKeyFrameRequestCallbackStatus + // Check callback + + // SetPacketLossBitrateAdaptationStatus + // Check bitrate changes/doesn't change + + // GetAvailableBandwidth + + // SendKeyFrame + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViECodec Extended Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViECodec Extended Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; + +} + +int ViEAutoTest::ViECodecAPITest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViECodec API Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + VideoEngine* ptrViE = NULL; + ptrViE = VideoEngine::Create(); + numberOfErrors += ViETest::TestError(ptrViE != NULL, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViEBase* ptrViEBase = ViEBase::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViEBase != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + error = ptrViEBase->Init(); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + int videoChannel = -1; + error = ptrViEBase->CreateChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViECodec* ptrViECodec = ViECodec::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViECodec != NULL, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + + // + // SendCodec + // + webrtc::VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + + const int numberOfCodecs = ptrViECodec->NumberOfCodecs(); + numberOfErrors += ViETest::TestError(numberOfCodecs > 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + for (int idx = 0; idx < numberOfCodecs; idx++) + { + error = ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + if (videoCodec.codecType == webrtc::kVideoCodecVP8) + { + error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + break; + } + } + memset(&videoCodec, 0, sizeof(videoCodec)); + error = ptrViECodec->GetSendCodec(videoChannel, videoCodec); + assert(videoCodec.codecType == webrtc::kVideoCodecVP8); + + for (int idx = 0; idx < numberOfCodecs; idx++) + { + error = ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + if (videoCodec.codecType == webrtc::kVideoCodecI420) + { + error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + break; + } + } + memset(&videoCodec, 0, sizeof(videoCodec)); + error = ptrViECodec->GetSendCodec(videoChannel, videoCodec); + assert(videoCodec.codecType == webrtc::kVideoCodecI420); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + error = ptrViEBase->DeleteChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + int remainingInterfaces = 0; + remainingInterfaces = ptrViECodec->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + remainingInterfaces = ptrViEBase->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + bool deleted = VideoEngine::Delete(ptrViE); + numberOfErrors += ViETest::TestError(deleted == true, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViECodec API Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViECodec API Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + +#ifdef WEBRTC_VIDEO_ENGINE_EXTERNAL_CODEC_API +#include "vie_external_codec.h" +#endif +int ViEAutoTest::ViECodecExternalCodecTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEExternalCodec Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + +#ifdef WEBRTC_VIDEO_ENGINE_EXTERNAL_CODEC_API + int numberOfErrors=0; + { + int error=0; + tbInterfaces ViE("ViEExternalCodec", numberOfErrors); + tbCaptureDevice captureDevice(ViE, numberOfErrors); + tbVideoChannel channel(ViE, numberOfErrors, webrtc::kVideoCodecI420, + 352,288,30,(352*288*3*8*30)/(2*1000)); + + captureDevice.ConnectTo(channel.videoChannel); + + error = ViE.ptrViERender->AddRenderer(channel.videoChannel, _window1, 0, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(channel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + channel.StartReceive(); + channel.StartSend(); + + ViETest::Log("Using internal I420 codec"); + AutoTestSleep(KAutoTestSleepTimeMs/2); + + ViEExternalCodec* ptrViEExtCodec = + ViEExternalCodec::GetInterface(ViE.ptrViE); + numberOfErrors += ViETest::TestError(ptrViEExtCodec != NULL, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + webrtc::VideoCodec codecStruct; + + error=ViE.ptrViECodec->GetSendCodec(channel.videoChannel,codecStruct); + numberOfErrors += ViETest::TestError(ptrViEExtCodec != NULL, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Use external encoder instead + { + tbI420Encoder extEncoder; + + // Test to register on wrong channel + error = ptrViEExtCodec->RegisterExternalSendCodec( + channel.videoChannel+5,codecStruct.plType,&extEncoder); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError( + ViE.LastError() == kViECodecInvalidArgument, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViEExtCodec->RegisterExternalSendCodec( + channel.videoChannel,codecStruct.plType,&extEncoder); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Use new external encoder + error = ViE.ptrViECodec->SetSendCodec(channel.videoChannel,codecStruct); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + tbI420Decoder extDecoder; + error = ptrViEExtCodec->RegisterExternalReceiveCodec( + channel.videoChannel,codecStruct.plType,&extDecoder); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViECodec->SetReceiveCodec(channel.videoChannel, + codecStruct); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Using external I420 codec"); + AutoTestSleep(KAutoTestSleepTimeMs); + + // Test to deregister on wrong channel + error = ptrViEExtCodec->DeRegisterExternalSendCodec( + channel.videoChannel+5,codecStruct.plType); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError( + ViE.LastError() == kViECodecInvalidArgument, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + // Test to deregister wrong payload type. + error = ptrViEExtCodec->DeRegisterExternalSendCodec( + channel.videoChannel,codecStruct.plType-1); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Deregister external send codec + error = ptrViEExtCodec->DeRegisterExternalSendCodec( + channel.videoChannel,codecStruct.plType); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViEExtCodec->DeRegisterExternalReceiveCodec( + channel.videoChannel,codecStruct.plType); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Verify that the encoder and decoder has been used + tbI420Encoder::FunctionCalls encodeCalls = + extEncoder.GetFunctionCalls(); + numberOfErrors += ViETest::TestError(encodeCalls.InitEncode == 1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(encodeCalls.Release == 1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(encodeCalls.Encode > 30, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError( + encodeCalls.RegisterEncodeCompleteCallback ==1, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(encodeCalls.SetRates > 1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(encodeCalls.SetPacketLoss > 1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + tbI420Decoder::FunctionCalls decodeCalls = + extDecoder.GetFunctionCalls(); + numberOfErrors += ViETest::TestError(decodeCalls.InitDecode == 1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(decodeCalls.Release == 1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(decodeCalls.Decode > 30, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError( + decodeCalls.RegisterDecodeCompleteCallback ==1, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + ViETest::Log("Changing payload type Using external I420 codec"); + + codecStruct.plType=codecStruct.plType-1; + error = ptrViEExtCodec->RegisterExternalReceiveCodec( + channel.videoChannel, codecStruct.plType, &extDecoder); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViECodec->SetReceiveCodec(channel.videoChannel, + codecStruct); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ptrViEExtCodec->RegisterExternalSendCodec( + channel.videoChannel, codecStruct.plType, &extEncoder); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Use new external encoder + error = ViE.ptrViECodec->SetSendCodec(channel.videoChannel, + codecStruct); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + AutoTestSleep(KAutoTestSleepTimeMs/2); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + + error = ptrViEExtCodec->DeRegisterExternalSendCodec( + channel.videoChannel,codecStruct.plType); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ptrViEExtCodec->DeRegisterExternalReceiveCodec( + channel.videoChannel,codecStruct.plType); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Verify that the encoder and decoder has been used + encodeCalls = extEncoder.GetFunctionCalls(); + numberOfErrors += ViETest::TestError(encodeCalls.InitEncode == 2, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(encodeCalls.Release == 2, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(encodeCalls.Encode > 30, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError( + encodeCalls.RegisterEncodeCompleteCallback == 2, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(encodeCalls.SetRates > 1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(encodeCalls.SetPacketLoss > 1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + decodeCalls = extDecoder.GetFunctionCalls(); + numberOfErrors += ViETest::TestError(decodeCalls.InitDecode == 2, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(decodeCalls.Release == 2, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(decodeCalls.Decode > 30, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError( + decodeCalls.RegisterDecodeCompleteCallback == 2, + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + int remainingInterfaces = ptrViEExtCodec->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } // tbI420Encoder and extDecoder goes out of scope + + ViETest::Log("Using internal I420 codec"); + AutoTestSleep(KAutoTestSleepTimeMs/2); + + } + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViEExternalCodec Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViEExternalCodec Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; + +#else + ViETest::Log(" ViEExternalCodec not enabled\n"); + return 0; +#endif +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_custom_call.cc b/video_engine/main/test/AutoTest/source/vie_autotest_custom_call.cc new file mode 100644 index 0000000000..35628696f1 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_custom_call.cc @@ -0,0 +1,950 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_autotest_custom_call.cc + * + */ + +#include "vie_autotest_defines.h" +#include "vie_autotest.h" + +#include + +int ViEAutoTest::ViECustomCall() +{ + + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" Enter values to use custom settings\n"); + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + std::string str; + + // VoE + VoiceEngine* ptrVE = VoiceEngine::Create(); + numberOfErrors += ViETest::TestError(ptrVE != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + VoEBase* ptrVEBase = VoEBase::GetInterface(ptrVE); + numberOfErrors += ViETest::TestError(ptrVEBase != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVEBase->Init(); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + VoECodec* ptrVECodec = VoECodec::GetInterface(ptrVE); + numberOfErrors += ViETest::TestError(ptrVECodec != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + VoEHardware* ptrVEHardware = VoEHardware::GetInterface(ptrVE); + numberOfErrors += ViETest::TestError(ptrVEHardware != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + VoEAudioProcessing* ptrVEAPM = VoEAudioProcessing::GetInterface(ptrVE); + numberOfErrors += ViETest::TestError(ptrVEAPM != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + + + // ViE + VideoEngine* ptrViE = NULL; + ptrViE = VideoEngine::Create(); + numberOfErrors += ViETest::TestError(ptrViE != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + ViEBase* ptrViEBase = ViEBase::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViEBase != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViEBase->Init(); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + ViECapture* ptrViECapture = ViECapture::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViECapture != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + ViERender* ptrViERender = ViERender::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViERender != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + ViECodec* ptrViECodec = ViECodec::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViECodec != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + ViENetwork* ptrViENetwork = ViENetwork::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViENetwork != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + + + bool startCall = false; + const unsigned int kMaxIPLength = 16; + char ipAddress[kMaxIPLength] = ""; + const unsigned int KMaxUniqueIdLength = 256; + char uniqueId[KMaxUniqueIdLength] = ""; + char deviceName[KMaxUniqueIdLength] = ""; + int videoTxPort = 0; + int videoRxPort = 0; + int videoChannel = -1; + int codecIdx = 0; + webrtc::VideoCodec videoCodec; + char audioCaptureDeviceName[KMaxUniqueIdLength] = ""; + char audioPlaybackDeviceName[KMaxUniqueIdLength] = ""; + int audioCaptureDeviceIndex = -1; + int audioPlaybackDeviceIndex = -1; + int audioTxPort = 0; + int audioRxPort = 0; + webrtc::CodecInst audioCodec; + int audioChannel = -1; + + while(1) + { + // IP + memset(ipAddress, 0, kMaxIPLength); + GetIPAddress(ipAddress); + + // video devices + memset(deviceName, 0, KMaxUniqueIdLength); + memset(uniqueId, 0, KMaxUniqueIdLength); + GetVideoDevice(ptrViEBase, ptrViECapture, deviceName, uniqueId); + + // video ports + videoTxPort = 0; + videoRxPort = 0; + GetVideoPorts(&videoTxPort, &videoRxPort); + + + // video codecs + memset((void*)&videoCodec, 0, sizeof(videoCodec)); + GetVideoCodec(ptrViECodec, videoCodec); + + + + // audio devices + memset(audioCaptureDeviceName, 0, KMaxUniqueIdLength); + memset(audioPlaybackDeviceName, 0, KMaxUniqueIdLength); + GetAudioDevices(ptrVEBase, ptrVEHardware, audioCaptureDeviceName, audioCaptureDeviceIndex, audioPlaybackDeviceName, audioPlaybackDeviceIndex); + + + // audio port + audioTxPort = 0; + audioRxPort = 0; + GetAudioPorts(&audioTxPort, &audioRxPort); + + // audio codec + memset((void*)&audioCodec, 0, sizeof(audioCodec)); + GetAudioCodec(ptrVECodec, audioCodec); + + // start the call now + PrintCallInformation(ipAddress, + deviceName, uniqueId, videoCodec, videoTxPort, videoRxPort, + audioCaptureDeviceName, audioPlaybackDeviceName, audioCodec, audioTxPort, audioRxPort); + + std::cout << std::endl; + std::cout << "1. Start the call" << std::endl; + std::cout << "2. Reconfigure call settings" << std::endl; + std::cout << "3. Go back to main menu" << std::endl; + std::cout << "What do you want to do? Press enter for default (Start the call): "; + + std::getline(std::cin, str); + int selection = 0; + selection = atoi(str.c_str()); + + if(selection == 0 || selection == 1){ + startCall = true; + break; + } + else if(selection == 2) + { + continue; + } + else if(selection == 3) + { + startCall = false; + break; + } + else + { + // invalid selection + std::cout << "ERROR: Code=" << error << " Invalid selection" << std::endl; + continue; + } + } + + + + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + + if(startCall == true) + { + + // Configure Audio first + audioChannel = ptrVEBase->CreateChannel(); + + error = ptrVEBase->SetSendDestination(audioChannel, audioTxPort, ipAddress); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVEBase->SetLocalReceiver(audioChannel, audioRxPort); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVEHardware->SetRecordingDevice(audioCaptureDeviceIndex); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVEHardware->SetPlayoutDevice(audioPlaybackDeviceIndex); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVECodec->SetSendCodec(audioChannel, audioCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVECodec->SetVADStatus(audioChannel, true, webrtc::kVadAggressiveHigh ); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVEAPM->SetAgcStatus(true, kAgcDefault); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVEAPM->SetNsStatus(true, kNsHighSuppression); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + // Configure Video now + + error = ptrViE->SetTraceFile("ViECustomCall.txt"); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViEBase->SetVoiceEngine(ptrVE); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViEBase->CreateChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViEBase->ConnectAudioChannel(videoChannel, audioChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + int captureId = 0; + error = ptrViECapture->AllocateCaptureDevice(uniqueId, KMaxUniqueIdLength, captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + ViERTP_RTCP* ptrViERtpRtcp = ViERTP_RTCP::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(ptrViE != NULL, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetRTCPStatus(videoChannel, kRtcpCompound_RFC4585); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetKeyFrameRequestMethod(videoChannel, kViEKeyFrameRequestPliRtcp); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetTMMBRStatus(videoChannel, true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViERender->AddRenderer(captureId, _window1, 0, 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + + error = ptrViERender->AddRenderer(videoChannel, _window2, 1, 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViENetwork->SetSendDestination(videoChannel, ipAddress, videoTxPort); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViENetwork->SetLocalReceiver(videoChannel, videoRxPort); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + + + // **** start the engines + // VE first + error = ptrVEBase->StartReceive(audioChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVEBase->StartPlayout(audioChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVEBase->StartSend(audioChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + + // ViE next + error = ptrViEBase->StartSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViEBase->StartReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViERender->MirrorRenderStream(captureId, true, false, true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViERender->StartRender(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViERender->StartRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + + + //*************************************************************** + // Engine ready. Wait for input + //*************************************************************** + + + // Call started + std::cout << std::endl; + std::cout << "Loopback call started" << std::endl; + std::cout << std::endl << std::endl; + std::cout << "Press enter to stop..."; + std::getline(std::cin, str); + + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + + // audio engine first + error = ptrVEBase->StopReceive(audioChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVEBase->StopPlayout(audioChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrVEBase->DeleteChannel(audioChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + + + + + // now do video + error = ptrViEBase->DisconnectAudioChannel(videoChannel); + + error = ptrViEBase->StopReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViEBase->StopSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViERender->StopRender(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViERender->StopRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViERender->RemoveRenderer(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViERender->RemoveRenderer(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViECapture->StopCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViECapture->DisconnectCaptureDevice(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViECapture->ReleaseCaptureDevice(captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ptrViEBase->DeleteChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + int remainingInterfaces = 0; + remainingInterfaces = ptrViECodec->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + remainingInterfaces = ptrViECapture->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + remainingInterfaces = ptrViERtpRtcp->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + remainingInterfaces = ptrViERender->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + remainingInterfaces = ptrViENetwork->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + remainingInterfaces = ptrViEBase->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + bool deleted = VideoEngine::Delete(ptrViE); + numberOfErrors += ViETest::TestError(deleted == true, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + ViETest::Log(" "); + ViETest::Log(" ViE Autotest Loopback Call Done"); + ViETest::Log("========================================"); + ViETest::Log(" "); + } + + return numberOfErrors; + +} + + + + + + + + + +bool ViEAutoTest::GetVideoDevice(ViEBase* ptrViEBase, ViECapture* ptrViECapture, char* captureDeviceName, char* captureDeviceUniqueId) +{ + int error = 0; + int numberOfErrors = 0; + int captureDeviceIndex = 0; + std::string str; + + const unsigned int KMaxDeviceNameLength = 128; + const unsigned int KMaxUniqueIdLength = 256; + char deviceName[KMaxDeviceNameLength]; + char uniqueId[KMaxUniqueIdLength]; + + + while(1) + { + memset(deviceName, 0, KMaxDeviceNameLength); + memset(uniqueId, 0, KMaxUniqueIdLength); + + std::cout << std::endl; + std::cout << "Available capture devices:" << std::endl; + int captureIdx = 0; + for (captureIdx = 0; captureIdx < ptrViECapture->NumberOfCaptureDevices(); captureIdx++) + { + memset(deviceName, 0, KMaxDeviceNameLength); + memset(uniqueId, 0, KMaxUniqueIdLength); + + error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName, KMaxDeviceNameLength, uniqueId, KMaxUniqueIdLength); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + std::cout << " " << captureIdx+1 << ". " << deviceName << std::endl; + } + std::cout << "Choose a capture device. Press enter for default (" << deviceName << "/" << uniqueId << "): "; + std::getline(std::cin, str); + captureDeviceIndex = atoi(str.c_str()); + + if(captureDeviceIndex == 0) + { + // use default (or first) camera + error = ptrViECapture->GetCaptureDevice(0, deviceName, KMaxDeviceNameLength, uniqueId, KMaxUniqueIdLength); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + strcpy(captureDeviceUniqueId, uniqueId); + strcpy(captureDeviceName, deviceName); + return true; + } + else if(captureDeviceIndex < 0 || captureDeviceIndex > (int)ptrViECapture->NumberOfCaptureDevices()) + { + // invalid selection + continue; + } + else + { + error = ptrViECapture->GetCaptureDevice(captureDeviceIndex - 1, deviceName, KMaxDeviceNameLength, uniqueId, KMaxUniqueIdLength); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + strcpy(captureDeviceName, uniqueId); + strcpy(captureDeviceName, deviceName); + return true; + } + } +} + +bool ViEAutoTest::GetAudioDevices(VoEBase* ptrVEBase, VoEHardware* ptrVEHardware, + char* recordingDeviceName, int& recordingDeviceIndex, + char* playbackDeviceName, int& playbackDeviceIndex) +{ + int error = 0; + int numberOfErrors = 0; + int captureDeviceIndex = 0; + std::string str; + + const unsigned int KMaxDeviceNameLength = 128; + const unsigned int KMaxUniqueIdLength = 128; + char recordingDeviceUniqueName[KMaxDeviceNameLength]; + char playbackDeviceUniqueName[KMaxUniqueIdLength]; + + int numberOfRecordingDevices = -1; + error = ptrVEHardware->GetNumOfRecordingDevices(numberOfRecordingDevices); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + while(1) + { + recordingDeviceIndex = -1; + + std::cout << std::endl; + std::cout << "Available audio capture devices:" << std::endl; + int captureIdx = 0; + + for (captureIdx = 0; captureIdx < numberOfRecordingDevices ; captureIdx++) + { + memset(recordingDeviceName, 0, KMaxDeviceNameLength); + memset(recordingDeviceUniqueName, 0, KMaxDeviceNameLength); + error = ptrVEHardware->GetRecordingDeviceName(captureIdx, recordingDeviceName, recordingDeviceUniqueName); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + std::cout << " " << captureIdx+1 << ". " << recordingDeviceName << std::endl; + } + + std::cout << "Choose an audio capture device. Press enter for default (" << recordingDeviceName << "): "; + std::getline(std::cin, str); + int captureDeviceIndex = atoi(str.c_str()); + + if(captureDeviceIndex == 0) + { + // use default (or first) camera + recordingDeviceIndex = 0; + error = ptrVEHardware->GetRecordingDeviceName(recordingDeviceIndex, recordingDeviceName, recordingDeviceUniqueName); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + break; + } + else if(captureDeviceIndex < 0 || captureDeviceIndex > numberOfRecordingDevices) + { + // invalid selection + continue; + } + else + { + recordingDeviceIndex = captureDeviceIndex - 1; + error = ptrVEHardware->GetRecordingDeviceName(recordingDeviceIndex, recordingDeviceName, recordingDeviceUniqueName); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + break; + } + } + + int numberOfPlaybackDevices = -1; + error = ptrVEHardware->GetNumOfPlayoutDevices(numberOfPlaybackDevices); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + while(1) + { + playbackDeviceIndex = -1; + + std::cout << std::endl; + std::cout << "Available audio playout devices:" << std::endl; + int captureIdx = 0; + + for (captureIdx = 0; captureIdx < numberOfPlaybackDevices ; captureIdx++) + { + memset(playbackDeviceName, 0, KMaxDeviceNameLength); + memset(playbackDeviceUniqueName, 0, KMaxDeviceNameLength); + error = ptrVEHardware->GetPlayoutDeviceName(captureIdx, playbackDeviceName, playbackDeviceUniqueName); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + std::cout << " " << captureIdx+1 << ". " << playbackDeviceName << std::endl; + } + + std::cout << "Choose an audio playback device. Press enter for default (" << playbackDeviceName << "): "; + std::getline(std::cin, str); + int captureDeviceIndex = atoi(str.c_str()); + + if(captureDeviceIndex == 0) + { + // use default (or first) camera + playbackDeviceIndex = 0; + error = ptrVEHardware->GetPlayoutDeviceName(playbackDeviceIndex, playbackDeviceName, playbackDeviceUniqueName); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + return true; + } + else if(captureDeviceIndex < 0 || captureDeviceIndex > numberOfPlaybackDevices) + { + // invalid selection + continue; + } + else + { + playbackDeviceIndex = captureDeviceIndex - 1; + error = ptrVEHardware->GetPlayoutDeviceName(playbackDeviceIndex, playbackDeviceName, playbackDeviceUniqueName); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + return true; + } + } + + + + +} + + +// general settings functions +bool ViEAutoTest::GetIPAddress(char* iIP) +{ + int error = 0; + char oIP[16] = DEFAULT_SEND_IP; + std::string str; + + while(1) + { + std::cout << std::endl; + std::cout << "Enter destination IP. Press enter for default (" << oIP << "): "; + std::getline(std::cin, str); + + if(str.compare("") == 0) + { + // use default value; + strcpy(iIP, oIP); + return true; + } + + if(ValidateIP(str) == false) + { + std::cout << "Invalid entry. Try again." << std::endl; + continue; + } + + // done. Copy std::string to c_string and return + strcpy(iIP, str.c_str()); + return true; + } + + assert(false); // should never reach here + return false; +} + +bool ViEAutoTest::ValidateIP(std::string iStr) +{ + if(0 == iStr.compare("")){ + return false; + } + + return true; +} + +// video settings functions +bool ViEAutoTest::GetVideoPorts(int* txPort, int* rxPort) +{ + int error = 0; + std::string str; + int port = 0; + + // set to default values + *txPort = DEFAULT_VIDEO_PORT; + *rxPort = DEFAULT_VIDEO_PORT; + + while(1) + { + std::cout << "Enter video send port. Press enter for default (" << *txPort << ")"; + std::getline(std::cin, str); + port = atoi(str.c_str()); + + if(port == 0) + { + // default value + break; + } + else + { + // user selection + if(port <= 0 || port > 63556) + { + // invalid selection + continue; + } + else + { + *txPort = port; + break; // move on to rxport + } + } + } + + while(1) + { + std::cout << "Enter video receive port. Press enter for default (" << *rxPort << ")"; + std::getline(std::cin, str); + port = atoi(str.c_str()); + + + if(port == 0) + { + // default value + return true; + } + else + { + // user selection + if(port <= 0 || port > 63556) + { + // invalid selection + continue; + } + else + { + *rxPort = port; + break; // move on to rxport + } + } + } + + assert(false); + return false; +} +bool ViEAutoTest::GetVideoCodec(ViECodec* ptrViECodec, webrtc::VideoCodec& videoCodec) +{ + int error = 0; + int numberOfErrors = 0; + int codecSelection = 0; + std::string str; + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + + bool exitLoop=false; + while(!exitLoop) + { + std::cout << std::endl; + std::cout << "Available video codecs:" << std::endl; + int codecIdx = 0; + int defaultCodecIdx = 0; + for (codecIdx = 0; codecIdx < ptrViECodec->NumberOfCodecs(); codecIdx++) + { + error = ptrViECodec->GetCodec(codecIdx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + // test for default codec index + if(strcmp(videoCodec.plName, DEFAULT_VIDEO_CODEC) == 0){ + defaultCodecIdx = codecIdx; + } + + std::cout << " " << codecIdx+1 << ". " << videoCodec.plName << std::endl; + } + std::cout << std::endl; + std::cout << "Choose video codec. Press enter for default (" << DEFAULT_VIDEO_CODEC << ")"; + std::getline(std::cin, str); + codecSelection = atoi(str.c_str()); + + + if(codecSelection == 0) + { + // use default + error = ptrViECodec->GetCodec(defaultCodecIdx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + exitLoop=true; + } + else + { + // user selection + codecSelection = atoi(str.c_str())-1; + error = ptrViECodec->GetCodec(codecSelection, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + if(error != 0) + { + std::cout << "ERROR: Code=" << error << " Invalid selection" << std::endl; + continue; + } + exitLoop=true; + } + } + + std::cout << "Choose video width. Press enter for default (" + << DEFAULT_VIDEO_CODEC_WIDTH << ")"; + std::getline(std::cin, str); + int sizeSelection = atoi(str.c_str()); + if(sizeSelection!=0) + { + videoCodec.width=sizeSelection; + } + + std::cout << "Choose video height. Press enter for default (" + << DEFAULT_VIDEO_CODEC_HEIGHT << ")"; + std::getline(std::cin, str); + sizeSelection = atoi(str.c_str()); + if(sizeSelection!=0) + { + videoCodec.height=sizeSelection; + } + + + + return true; + +} + +// audio settings functions +bool ViEAutoTest::GetAudioPorts(int* txPort, int* rxPort) +{ + int error = 0; + int port = 0; + std::string str; + + // set to default values + *txPort = DEFAULT_AUDIO_PORT; + *rxPort = DEFAULT_AUDIO_PORT; + + while(1) + { + std::cout << "Enter audio send port. Press enter for default (" << *txPort << ")"; + std::getline(std::cin, str); + port = atoi(str.c_str()); + + if(port == 0) + { + // default value + break; + } + else + { + // user selection + if(port <= 0 || port > 63556) + { + // invalid selection + continue; + } + else + { + *txPort = port; + break; // move on to rxport + } + } + } + + while(1) + { + std::cout << "Enter audio receive port. Press enter for default (" << *rxPort << ")"; + std::getline(std::cin, str); + port = atoi(str.c_str()); + + if(port == 0) + { + // default value + return true; + } + else + { + // user selection + if(port <= 0 || port > 63556) + { + // invalid selection + continue; + } + else + { + *rxPort = port; + break; // move on to rxport + } + } + } + + assert(false); + return false; +} + +bool ViEAutoTest::GetAudioCodec(webrtc::VoECodec* ptrVeCodec, webrtc::CodecInst& audioCodec) +{ + int error = 0; + int numberOfErrors = 0; + int codecSelection = 0; + std::string str; + memset(&audioCodec, 0, sizeof(webrtc::CodecInst)); + + while(1) + { + std::cout << std::endl; + std::cout << "Available audio codecs:" << std::endl; + int codecIdx = 0; + int defaultCodecIdx = 0; + for (codecIdx = 0; codecIdx < ptrVeCodec->NumOfCodecs(); codecIdx++) + { + error = ptrVeCodec->GetCodec(codecIdx, audioCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + // test for default codec index + if(strcmp(audioCodec.plname, DEFAULT_AUDIO_CODEC) == 0){ + defaultCodecIdx = codecIdx; + } + + std::cout << " " << codecIdx+1 << ". " << audioCodec.plname << std::endl; + } + std::cout << std::endl; + std::cout << "Choose audio codec. Press enter for default (" << DEFAULT_AUDIO_CODEC << ")"; + std::getline(std::cin, str); + codecSelection = atoi(str.c_str()); + + if(codecSelection == 0) + { + // use default + error = ptrVeCodec->GetCodec(defaultCodecIdx, audioCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + return true; + } + else + { + // user selection + codecSelection = atoi(str.c_str())-1; + error = ptrVeCodec->GetCodec(codecSelection, audioCodec); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + if(error != 0) + { + std::cout << "ERROR: Code=" << error << " Invalid selection" << std::endl; + continue; + } + return true; + } + } + + assert(false); // should never reach here + return false; +} + + +void ViEAutoTest::PrintCallInformation(char* IP, + char* videoCaptureDeviceName, char* videoCaptureUniqueId, webrtc::VideoCodec videoCodec, int videoTxPort, int videoRxPort, + char* audioCaptureDeviceName, char* audioPlaybackDeviceName, webrtc::CodecInst audioCodec, int audioTxPort, int audioRxPort) +{ + std::string str; + + std::cout << "************************************************" << std::endl; + std::cout << "The call will use the following settings: " << std::endl; + std::cout << "\tIP: " << IP << std::endl; + std::cout << "\tVideo Capture Device: " << videoCaptureDeviceName << std::endl; + std::cout << "\t\tName: " << videoCaptureDeviceName << std::endl; + std::cout << "\t\tUniqueId: " << videoCaptureUniqueId << std::endl; + std::cout << "\tVideo Codec: " << std::endl; + std::cout << "\t\tplName: " << videoCodec.plName << std::endl; + std::cout << "\t\tplType: " << (int)videoCodec.plType << std::endl; + std::cout << "\t\twidth: " << videoCodec.width << std::endl; + std::cout << "\t\theight: " << videoCodec.height << std::endl; + std::cout << "\t Video Tx Port: " << videoTxPort << std::endl; + std::cout << "\t Video Rx Port: " << videoRxPort << std::endl; + std::cout << "\tAudio Capture Device: " << audioCaptureDeviceName << std::endl; + std::cout << "\tAudio Playback Device: " << audioPlaybackDeviceName << std::endl; + std::cout << "\tAudio Codec: " << std::endl; + std::cout << "\t\tplname: " << audioCodec.plname << std::endl; + std::cout << "\t\tpltype: " << (int)audioCodec.pltype << std::endl; + std::cout << "\t Audio Tx Port: " << audioTxPort << std::endl; + std::cout << "\t Audio Rx Port: " << audioRxPort << std::endl; + std::cout << "************************************************" << std::endl; + + +} + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_encryption.cc b/video_engine/main/test/AutoTest/source/vie_autotest_encryption.cc new file mode 100644 index 0000000000..49e1fa5600 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_encryption.cc @@ -0,0 +1,903 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_encryption.cc +// + +#include "vie_autotest_defines.h" +#include "vie_autotest.h" +#include "engine_configurations.h" + +#include "tb_capture_device.h" +#include "tb_external_transport.h" +#include "tb_interfaces.h" +#include "tb_video_channel.h" + +class ViEAutotestEncryption: public Encryption +{ +public: + ViEAutotestEncryption() + { + } + ~ViEAutotestEncryption() + { + } + + virtual void encrypt(int channel_no, unsigned char * in_data, + unsigned char * out_data, int bytes_in, int* bytes_out) + { + for (int i = 0; i < bytes_in; i++) + { + out_data[i] = ~in_data[i]; + } + *bytes_out = bytes_in + 2; + } + + virtual void decrypt(int channel_no, unsigned char * in_data, + unsigned char * out_data, int bytes_in, int* bytes_out) + { + for (int i = 0; i < bytes_in - 2; i++) + { + out_data[i] = ~in_data[i]; + } + *bytes_out = bytes_in - 2; + } + + virtual void encrypt_rtcp(int channel_no, unsigned char * in_data, + unsigned char * out_data, int bytes_in, + int* bytes_out) + { + for (int i = 0; i < bytes_in; i++) + { + out_data[i] = ~in_data[i]; + } + *bytes_out = bytes_in + 2; + } + + virtual void decrypt_rtcp(int channel_no, unsigned char * in_data, + unsigned char * out_data, int bytes_in, + int* bytes_out) + { + for (int i = 0; i < bytes_in - 2; i++) + { + out_data[i] = ~in_data[i]; + } + *bytes_out = bytes_in - 2; + } +}; + +int ViEAutoTest::ViEEncryptionStandardTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEEncryption Standard Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + // Create VIE + tbInterfaces ViE("ViEEncryptionStandardTest", numberOfErrors); + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + + // Create a capture device + tbCaptureDevice tbCapture(ViE, numberOfErrors); + tbCapture.ConnectTo(tbChannel.videoChannel); + + tbChannel.StartReceive(); + + tbChannel.StartSend(); + + error = ViE.ptrViERender->AddRenderer(tbCapture.captureId, _window1, 0, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->AddRenderer(tbChannel.videoChannel, _window2, 1, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + +#ifdef WEBRTC_SRTP + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + + // + // SRTP + // + unsigned char srtpKey1[30] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9}; + + // Encryption only + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthNull, 0, 0, webrtc::kEncryption, srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthNull, 0, 0, webrtc::kEncryption, srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("SRTP encryption only"); + AutoTestSleep(KAutoTestSleepTimeMs); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Authentication only + error = ViE.ptrViEEncryption->EnableSRTPReceive(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthHmacSha1, 20, + 4, webrtc::kAuthentication, + srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthHmacSha1, 20, 4, + webrtc::kAuthentication, + srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("SRTP authentication only"); + AutoTestSleep(KAutoTestSleepTimeMs); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Full protection + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("SRTP full protection"); + AutoTestSleep(KAutoTestSleepTimeMs); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", +#endif // WEBRTC_SRTP + // + // External encryption + // + ViEAutotestEncryption testEncryption; + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + error = ViE.ptrViEEncryption->RegisterExternalEncryption( + tbChannel.videoChannel, testEncryption); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log( + "External encryption/decryption added, you should still see video"); + AutoTestSleep(KAutoTestSleepTimeMs); + error = ViE.ptrViEEncryption->DeregisterExternalEncryption( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViEEncryption Standard Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViEEncryption Standard Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; + +} + +int ViEAutoTest::ViEEncryptionExtendedTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEEncryption Extended Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + // Create VIE + tbInterfaces ViE("ViEEncryptionExtendedTest", numberOfErrors); + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + + // Create a capture device + tbCaptureDevice tbCapture(ViE, numberOfErrors); + tbCapture.ConnectTo(tbChannel.videoChannel); + + tbChannel.StartReceive(); + tbChannel.StartSend(); + + error = ViE.ptrViERender->AddRenderer(tbCapture.captureId, _window1, 0, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->AddRenderer(tbChannel.videoChannel, _window2, 1, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + +#ifdef WEBRTC_SRTP + + // + // SRTP + // + unsigned char srtpKey1[30] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9}; + unsigned char srtpKey2[30] = + { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, + 5, 4, 3, 2, 1, 0}; + // NULL + error = ViE.ptrViEEncryption->EnableSRTPReceive(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthNull, 0, 0, + webrtc::kNoProtection, + srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthNull, 0, 0, + webrtc::kNoProtection, + srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("SRTP NULL encryption/authentication"); + AutoTestSleep(KAutoTestSleepTimeMs); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Encryption only + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthNull, 0, 0, webrtc::kEncryption, srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthNull, 0, 0, webrtc::kEncryption, srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("SRTP encryption only"); + AutoTestSleep(KAutoTestSleepTimeMs); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Authentication only + error = ViE.ptrViEEncryption->EnableSRTPReceive(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthHmacSha1, 20, + 4, webrtc::kAuthentication, + srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthHmacSha1, 20, 4, + webrtc::kAuthentication, + srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("SRTP authentication only"); + AutoTestSleep(KAutoTestSleepTimeMs); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Full protection + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("SRTP full protection"); + AutoTestSleep(KAutoTestSleepTimeMs); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Change receive key, but not send key... + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log( + "\nSRTP receive key changed, you should not see any remote images"); + AutoTestSleep(KAutoTestSleepTimeMs); + + // Change send key too + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("\nSRTP send key changed too, you should see remote video " + "again with some decoding artefacts at start"); + AutoTestSleep(KAutoTestSleepTimeMs); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Disable receive, keep send + ViETest::Log("SRTP receive disabled , you shouldn't see any video"); + AutoTestSleep(KAutoTestSleepTimeMs); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + +#endif //WEBRTC_SRTP + // + // External encryption + // + ViEAutotestEncryption testEncryption; + error + = ViE.ptrViEEncryption->RegisterExternalEncryption( + tbChannel.videoChannel, testEncryption); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log( + "External encryption/decryption added, you should still see video"); + AutoTestSleep(KAutoTestSleepTimeMs); + error + = ViE.ptrViEEncryption->DeregisterExternalEncryption( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViEEncryption Extended Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViEEncryption Extended Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + +int ViEAutoTest::ViEEncryptionAPITest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEEncryption API Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + // Create VIE + tbInterfaces ViE("ViEEncryptionAPITest", numberOfErrors); + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + + // Create a capture device + tbCaptureDevice tbCapture(ViE, numberOfErrors); + // Connect to channel + tbCapture.ConnectTo(tbChannel.videoChannel); + +#ifdef WEBRTC_SRTP + unsigned char srtpKey[30] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9}; + + // + // EnableSRTPSend and DisableSRTPSend + // + + // Incorrect input argument, complete protection not enabled + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kNoProtection, srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryption, srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kAuthentication, srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Incorrect cipher key length + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 15, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 257, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherNull, 15, webrtc::kAuthHmacSha1, + 20, 4, webrtc::kEncryptionAndAuthentication, srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherNull, 257, webrtc::kAuthHmacSha1, + 20, 4, webrtc::kEncryptionAndAuthentication, srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Incorrect auth key length + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, + 30, webrtc::kAuthHmacSha1, 21, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthNull, 257, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 21, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthNull, 20, 13, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // NULL input + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + NULL); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Double enable and disable + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // No protection + error = ViE.ptrViEEncryption->EnableSRTPSend(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthNull, 0, 0, + webrtc::kNoProtection, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Authentication only + error = ViE.ptrViEEncryption->EnableSRTPSend(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthHmacSha1, 20, 4, + webrtc::kAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthHmacSha1, 1, 4, + webrtc::kAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthHmacSha1, 20, 20, + webrtc::kAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthHmacSha1, 1, 1, + webrtc::kAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Encryption only + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthNull, 0, 0, webrtc::kEncryption, srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 16, + webrtc::kAuthNull, 0, 0, webrtc::kEncryption, srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Full protection + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // EnableSRTPReceive and DisableSRTPReceive + // + + // Incorrect input argument, complete protection not enabled + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kNoProtection, srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryption, srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kAuthentication, srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Incorrect cipher key length + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 15, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 257, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherNull, 15, webrtc::kAuthHmacSha1, + 20, 4, webrtc::kEncryptionAndAuthentication, srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherNull, 257, webrtc::kAuthHmacSha1, + 20, 4, webrtc::kEncryptionAndAuthentication, srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Incorrect auth key length + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 21, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthNull, 257, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 21, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthNull, 20, 13, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // NULL input + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + NULL); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Double enable and disable + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPSend( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // No protection + error = ViE.ptrViEEncryption->EnableSRTPReceive(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthNull, 0, 0, + webrtc::kNoProtection, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Authentication only + + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthHmacSha1, 1, 4, + webrtc::kAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthHmacSha1, 20, + 20, webrtc::kAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive(tbChannel.videoChannel, + webrtc::kCipherNull, 0, + webrtc::kAuthHmacSha1, 1, 1, + webrtc::kAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Encryption only + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthNull, 0, 0, webrtc::kEncryption, srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 16, + webrtc::kAuthNull, 0, 0, webrtc::kEncryption, srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Full protection + error = ViE.ptrViEEncryption->EnableSRTPReceive( + tbChannel.videoChannel, webrtc::kCipherAes128CounterMode, 30, + webrtc::kAuthHmacSha1, 20, 4, webrtc::kEncryptionAndAuthentication, + srtpKey); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DisableSRTPReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#endif //WEBRTC_SRTP + // + // External encryption + // + + ViEAutotestEncryption testEncryption; + error = ViE.ptrViEEncryption->RegisterExternalEncryption( + tbChannel.videoChannel, testEncryption); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->RegisterExternalEncryption( + tbChannel.videoChannel, testEncryption); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DeregisterExternalEncryption( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEEncryption->DeregisterExternalEncryption( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViEEncryption API Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViEEncryption API Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_file.cc b/video_engine/main/test/AutoTest/source/vie_autotest_file.cc new file mode 100644 index 0000000000..7668c5d102 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_file.cc @@ -0,0 +1,858 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_file.cc +// + +#include "vie_autotest_defines.h" +#include "vie_autotest.h" +#include "engine_configurations.h" + +#include "tb_interfaces.h" +#include "tb_capture_device.h" + +#include "voe_codec.h" + +// TODO: remove using ... +using namespace std; + +class ViEAutotestFileObserver: public ViEFileObserver +{ +public: + ViEAutotestFileObserver() {}; + ~ViEAutotestFileObserver() {}; + + void PlayFileEnded(const WebRtc_Word32 fileId) + { + ViETest::Log("PlayFile ended"); + } +}; + +int ViEAutoTest::ViEFileStandardTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEFile Standard Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + { + ViETest::Log("Starting a loopback call..."); + + tbInterfaces interfaces = tbInterfaces("ViEFileStandardTest", + numberOfErrors); + + VideoEngine* ptrViE = interfaces.ptrViE; + ViEBase* ptrViEBase = interfaces.ptrViEBase; + ViECapture* ptrViECapture = interfaces.ptrViECapture; + ViERender* ptrViERender = interfaces.ptrViERender; + ViECodec* ptrViECodec = interfaces.ptrViECodec; + ViERTP_RTCP* ptrViERtpRtcp = interfaces.ptrViERtpRtcp; + ViENetwork* ptrViENetwork = interfaces.ptrViENetwork; + + tbCaptureDevice captureDevice = tbCaptureDevice(interfaces, + numberOfErrors); + int captureId = captureDevice.captureId; + + int videoChannel = -1; + error = ptrViEBase->CreateChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetRTCPStatus(videoChannel, + kRtcpCompound_RFC4585); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetKeyFrameRequestMethod( + videoChannel, kViEKeyFrameRequestPliRtcp); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViERtpRtcp->SetTMMBRStatus(videoChannel, true); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViERender->AddRenderer(captureId, _window1, 0, 0.0, 0.0, + 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViERender->AddRenderer(videoChannel, _window2, 1, 0.0, 0.0, + 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViERender->StartRender(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViERender->StartRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + webrtc::VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + for (int idx = 0; idx < ptrViECodec->NumberOfCodecs(); idx++) + { + error = ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + } + + // Find the codec used for encoding the channel + for (int idx = 0; idx < ptrViECodec->NumberOfCodecs(); idx++) + { + error = ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + if (videoCodec.codecType == webrtc::kVideoCodecVP8) + { + error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + break; + } + } + // Find the codec used for recording. + for (int idx = 0; idx < ptrViECodec->NumberOfCodecs(); idx++) + { + error = ptrViECodec->GetCodec(idx, videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + if (videoCodec.codecType == webrtc::kVideoCodecI420) + { + break; + } + } + + + const char* ipAddress = "127.0.0.1"; + const unsigned short rtpPort = 6000; + error = ptrViENetwork->SetLocalReceiver(videoChannel, rtpPort); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViEBase->StartReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViENetwork->SetSendDestination(videoChannel, ipAddress, + rtpPort); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViEBase->StartSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + ViEFile* ptrViEFile = ViEFile::GetInterface(ptrViE); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + VoiceEngine* ptrVEEngine = VoiceEngine::Create(); + VoEBase* ptrVEBase = VoEBase::GetInterface(ptrVEEngine); + ptrVEBase->Init(); + + int audioChannel = ptrVEBase->CreateChannel(); + ptrViEBase->SetVoiceEngine(ptrVEEngine); + ptrViEBase->ConnectAudioChannel(videoChannel, audioChannel); + + webrtc::CodecInst audioCodec; + webrtc::VoECodec* ptrVECodec = + webrtc::VoECodec::GetInterface(ptrVEEngine); + for (int index = 0; index < ptrVECodec->NumOfCodecs(); index++) + { + ptrVECodec->GetCodec(index, audioCodec); + if (0 == strcmp(audioCodec.plname, "PCMU") || 0 + == strcmp(audioCodec.plname, "PCMA")) + { + break; // these two types are allowed as avi recording formats + } + } + + webrtc::CodecInst audioCodec2; + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + // Call started + ViETest::Log("Call started\nYou should see local preview from camera\n" + "in window 1 and the remote video in window 2."); + AutoTestSleep(2000); + + const int RENDER_TIMEOUT = 1000; + const int TEST_SPACING = 1000; + const int UI_UPDATE_INTERVAL = 2000; + const int VIDEO_LENGTH = 5000; + + + const char renderStartImage[1024] = VIE_TEST_FILES_ROOT "renderStartImage.jpg"; + const char captureDeviceImage[1024] = VIE_TEST_FILES_ROOT "captureDeviceImage.jpg"; + const char renderTimeoutFile[1024] = VIE_TEST_FILES_ROOT "renderTimeoutImage.jpg"; + const char snapshotCaptureDeviceFileName[256] = VIE_TEST_FILES_ROOT + "snapshotCaptureDevice.jpg"; + const char incomingVideo[1024] = VIE_TEST_FILES_ROOT "incomingVideo.avi"; + const char outgoingVideo[1024] = VIE_TEST_FILES_ROOT "outgoingVideo.avi"; + char snapshotRenderFileName[256] = VIE_TEST_FILES_ROOT "snapshotRenderer.jpg"; + + ViEPicture capturePicture; + ViEPicture renderPicture; + ViEPicture renderTimeoutPicture; // TODO: init with and image + + ViEAutotestFileObserver fileObserver; + int fileId; + + AutoTestSleep(TEST_SPACING); + + // testing StartRecordIncomingVideo and StopRecordIncomingVideo + { + ViETest::Log("Recording incoming video (currently no audio) for %d " + "seconds", VIDEO_LENGTH); + + error = ptrViEFile->StartRecordIncomingVideo(videoChannel, + incomingVideo, + NO_AUDIO, audioCodec2, + videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + AutoTestSleep(VIDEO_LENGTH); + ViETest::Log("Stop recording incoming video"); + + error = ptrViEFile->StopRecordIncomingVideo(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Done\n"); + } + + AutoTestSleep(TEST_SPACING); + + // testing GetFileInformation + { + webrtc::VideoCodec fileVideoCodec; + webrtc::CodecInst fileAudioCodec; + ViETest::Log("Reading video file information"); + + error = ptrViEFile->GetFileInformation(incomingVideo, + fileVideoCodec, + fileAudioCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + PrintAudioCodec(fileAudioCodec); + PrintVideoCodec(fileVideoCodec); + } + + // testing StartPlayFile and RegisterObserver + { + ViETest::Log("Start playing file: %s with observer", incomingVideo); + error = ptrViEFile->StartPlayFile(incomingVideo, fileId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + ViETest::Log("Registering file observer"); + error = ptrViEFile->RegisterObserver(fileId, fileObserver); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + ViETest::Log("Done\n"); + } + + // testing SendFileOnChannel and StopSendFileOnChannel + { + ViETest::Log("Sending video on channel"); + // should fail since we are sending the capture device. + error = ptrViEFile->SendFileOnChannel(fileId, videoChannel); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + // Disconnect the camera + error = ptrViECapture->DisconnectCaptureDevice(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + // And try playing the file again. + error = ptrViEFile->SendFileOnChannel(fileId, videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + AutoTestSleep(VIDEO_LENGTH); + ViETest::Log("Stopped sending video on channel"); + error = ptrViEFile->StopSendFileOnChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Done\n"); + } + + AutoTestSleep(TEST_SPACING); + + // stop playing the file + { + ViETest::Log("Stop playing the file."); + error = ptrViEFile->StopPlayFile(fileId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Done\n"); + } + + // testing StartRecordOutgoingVideo and StopRecordOutgoingVideo + { + // connect the camera to the output. + error = ptrViECapture->ConnectCaptureDevice(captureId, + videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + ViETest::Log("Recording outgoing video (currently no audio) for %d " + "seconds", VIDEO_LENGTH); + error = ptrViEFile->StartRecordOutgoingVideo(videoChannel, + outgoingVideo, + NO_AUDIO, audioCodec2, + videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + AutoTestSleep(VIDEO_LENGTH); + ViETest::Log("Stop recording outgoing video"); + error = ptrViEFile->StopRecordOutgoingVideo(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Done\n"); + } + + // again testing GetFileInformation + { + error = ptrViEFile->GetFileInformation(incomingVideo, videoCodec, + audioCodec2); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + PrintAudioCodec(audioCodec2); + PrintVideoCodec(videoCodec); + } + + AutoTestSleep(TEST_SPACING); + + // GetCaptureDeviceSnapshot + { + ViETest::Log("Testing GetCaptureDeviceSnapshot(int, ViEPicture)"); + ViETest::Log("Taking a picture to use for displaying ViEPictures " + "for the rest of file test"); + ViETest::Log("Hold an object to the camera. Ready?..."); + AutoTestSleep(1000); + ViETest::Log("3"); + AutoTestSleep(1000); + ViETest::Log("...2"); + AutoTestSleep(1000); + ViETest::Log("...1"); + AutoTestSleep(1000); + ViETest::Log("...Taking picture!"); + error = ptrViEFile->GetCaptureDeviceSnapshot(captureId, + capturePicture); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Remove paper. Picture has been taken"); + AutoTestSleep(TEST_SPACING); + + ViETest::Log("Done\n"); + } + + AutoTestSleep(TEST_SPACING); + + // GetRenderSnapshot + { + ViETest::Log("Testing GetRenderSnapshot(int, char*)"); + + ViETest::Log("Taking snapshot of videoChannel %d", captureId); + error = ptrViEFile->GetRenderSnapshot(captureId, + snapshotRenderFileName); + ViETest::Log("Wrote image to file %s", snapshotRenderFileName); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Done\n"); + AutoTestSleep(TEST_SPACING); + } + + // GetRenderSnapshot + { + ViETest::Log("Testing GetRenderSnapshot(int, ViEPicture)"); + error = ptrViEFile->GetRenderSnapshot(captureId, renderPicture); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Done\n"); + } + + AutoTestSleep(TEST_SPACING); + + // GetCaptureDeviceSnapshot + { + ViETest::Log("Testing GetCaptureDeviceSnapshot(int, char*)"); + ViETest::Log("Taking snapshot from capture device %d", captureId); + error = ptrViEFile->GetCaptureDeviceSnapshot( + captureId, snapshotCaptureDeviceFileName); + ViETest::Log("Wrote image to file %s", + snapshotCaptureDeviceFileName); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Done\n"); + } + + AutoTestSleep(TEST_SPACING); + + // Testing: SetCaptureDeviceImage + { + ViETest::Log("Testing SetCaptureDeviceImage(int, char*)"); + error = ptrViECapture->StopCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViEFile->SetCaptureDeviceImage(captureId, + captureDeviceImage); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + ViETest::Log("you should see the capture device image now"); + AutoTestSleep(2 * RENDER_TIMEOUT); + error = ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Done\n"); + } + + AutoTestSleep(TEST_SPACING); + + // Testing: SetCaptureDeviceImage + { + ViETest::Log("Testing SetCaptureDeviceImage(int, ViEPicture)"); + error = ptrViECapture->StopCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error + = ptrViEFile->SetCaptureDeviceImage(captureId, capturePicture); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + ViETest::Log("you should see the capture device image now"); + AutoTestSleep(2 * RENDER_TIMEOUT); + error = ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Done\n"); + } + + AutoTestSleep(TEST_SPACING); + + // testing SetRenderStartImage(videoChannel, renderStartImage); + { + ViETest::Log("Testing SetRenderStartImage(int, char*)"); + // set render image, then stop capture and stop render to display it + ViETest::Log("Stoping renderer, setting start image, then " + "restarting"); + error = ptrViEFile->SetRenderStartImage(videoChannel, + renderStartImage); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + error = ptrViECapture->StopCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + error = ptrViERender->StopRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + ViETest::Log("Render start image should be displayed."); + AutoTestSleep(RENDER_TIMEOUT); + + // restarting capture and render + error = ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViERender->StartRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Done\n"); + } + + AutoTestSleep(TEST_SPACING); + + // testing SetRenderStartImage(videoChannel, renderStartImage); + { + ViETest::Log("Testing SetRenderStartImage(int, ViEPicture)"); + // set render image, then stop capture and stop render to display it + ViETest::Log("Stoping renderer, setting start image, then " + "restarting"); + error = ptrViEFile->SetRenderStartImage(videoChannel, + capturePicture); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + error = ptrViECapture->StopCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + error = ptrViERender->StopRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + ViETest::Log("Render start image should be displayed."); + AutoTestSleep(RENDER_TIMEOUT); + + // restarting capture and render + error = ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + error = ptrViERender->StartRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Done\n"); + } + + AutoTestSleep(TEST_SPACING); + + // testing SetRenderTimeoutImage(videoChannel, renderTimeoutFile, + // RENDER_TIMEOUT); + { + ViETest::Log("Testing SetRenderTimeoutImage(int, char*)"); + ViETest::Log("Stopping capture device to induce timeout of %d ms", + RENDER_TIMEOUT); + error = ptrViEFile->SetRenderTimeoutImage(videoChannel, + renderTimeoutFile, + RENDER_TIMEOUT); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + // now stop sending frames to the remote renderer and wait for + // timeout + error = ptrViECapture->StopCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + AutoTestSleep(RENDER_TIMEOUT); + ViETest::Log("Timeout image should be displayed now for %d ms", + RENDER_TIMEOUT * 2); + AutoTestSleep(RENDER_TIMEOUT * 2); + + // restart the capture device to undo the timeout + error = ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Restarting capture device"); + AutoTestSleep(RENDER_TIMEOUT); + ViETest::Log("Done\n"); + } + + AutoTestSleep(TEST_SPACING); + + // Need to create a ViEPicture object to pass into this function. + // SetRenderTimeoutImage(videoChannel, renderTimeoutFile, + // RENDER_TIMEOUT); + { + ViETest::Log("Testing SetRenderTimeoutImage(int, ViEPicture)"); + ViETest::Log("Stopping capture device to induce timeout of %d", + RENDER_TIMEOUT); + error = ptrViEFile->SetRenderTimeoutImage(videoChannel, + capturePicture, + RENDER_TIMEOUT); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + // now stop sending frames to the remote renderer and wait for + // timeout + error = ptrViECapture->StopCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + AutoTestSleep(RENDER_TIMEOUT); + ViETest::Log("Timeout image should be displayed now for %d", + RENDER_TIMEOUT * 2); + AutoTestSleep(RENDER_TIMEOUT * 2); + + // restart the capture device to undo the timeout + error = ptrViECapture->StartCapture(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + ViETest::Log("Restarting capture device"); + ViETest::Log("Done\n"); + } + + // testing DeregisterObserver + { + ViETest::Log("Deregistering file observer"); + // Should fail since we don't observe this file. + error = ptrViEFile->DeregisterObserver(fileId, fileObserver); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + } + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + + error = ptrViEBase->StopReceive(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViEBase->StopSend(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViERender->StopRender(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViERender->RemoveRenderer(captureId); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViERender->RemoveRenderer(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViECapture->DisconnectCaptureDevice(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViEFile->FreePicture(capturePicture); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViEFile->FreePicture(renderPicture); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViEFile->FreePicture(renderTimeoutPicture); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + error = ptrViEBase->DeleteChannel(videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + int remainingInterfaces = 0; + + remainingInterfaces = ptrViEFile->Release(); + numberOfErrors += ViETest::TestError(remainingInterfaces == 0, + "ERROR:%d %s at line %d", + ptrViEBase->LastError(), + __FUNCTION__, __LINE__); + + } + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViEFile API Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViEFile Standard Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + + return 0; +} + +int ViEAutoTest::ViEFileExtendedTest() +{ + + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEFile Extended Test\n"); + + ViETest::Log(" "); + ViETest::Log(" ViEFile Extended Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + +int ViEAutoTest::ViEFileAPITest() +{ + + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEFile API Test- nothing tested. Only tested in Standard test.\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + + + ViETest::Log(" "); + ViETest::Log(" ViEFile API Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_image_process.cc b/video_engine/main/test/AutoTest/source/vie_autotest_image_process.cc new file mode 100644 index 0000000000..b71d839f3c --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_image_process.cc @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_image_process.cc +// + +// Settings +#include "vie_autotest_defines.h" +#include "vie_autotest.h" +#include "engine_configurations.h" + +#include "tb_interfaces.h" +#include "tb_video_channel.h" +#include "tb_capture_device.h" + +class MyEffectFilter: public ViEEffectFilter +{ +public: + MyEffectFilter() {} + + ~MyEffectFilter() {} + + virtual int Transform(int size, unsigned char* frameBuffer, + unsigned int timeStamp90KHz, unsigned int width, + unsigned int height) + { + // Black and white + memset(frameBuffer + (2 * size) / 3, 0x7f, size / 3); + return 0; + } +}; + +int ViEAutoTest::ViEImageProcessStandardTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEImageProcess Standard Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + int rtpPort = 6000; + // Create VIE + tbInterfaces ViE("ViEImageProcessAPITest", numberOfErrors); + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + // Create a capture device + tbCaptureDevice tbCapture(ViE, numberOfErrors); + + tbCapture.ConnectTo(tbChannel.videoChannel); + tbChannel.StartReceive(rtpPort); + tbChannel.StartSend(rtpPort); + + MyEffectFilter effectFilter; + + error = ViE.ptrViERender->AddRenderer(tbCapture.captureId, _window1, 0, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->StartRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->AddRenderer(tbChannel.videoChannel, _window2, 1, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->StartRender(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Capture device is renderered in Window 1"); + ViETest::Log("Remote stream is renderered in Window 2"); + AutoTestSleep(KAutoTestSleepTimeMs); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + + error + = ViE.ptrViEImageProcess->RegisterCaptureEffectFilter( + tbCapture.captureId, effectFilter); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Black and white filter registered for capture device, " + "affects both windows"); + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViEImageProcess->DeregisterCaptureEffectFilter( + tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEImageProcess->RegisterRenderEffectFilter( + tbChannel.videoChannel, effectFilter); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Remove capture effect filter, adding filter for incoming " + "stream"); + ViETest::Log("Only Window 2 should be black and white"); + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViERender->StopRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->RemoveRenderer(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + int rtpPort2 = rtpPort + 100; + // Create a video channel + tbVideoChannel tbChannel2(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + + tbCapture.ConnectTo(tbChannel2.videoChannel); + tbChannel2.StartReceive(rtpPort2); + tbChannel2.StartSend(rtpPort2); + + error = ViE.ptrViERender->AddRenderer(tbChannel2.videoChannel, _window1, 1, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->StartRender(tbChannel2.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEImageProcess->DeregisterRenderEffectFilter( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Local renderer removed, added new channel and rendering in " + "Window1."); + + error = ViE.ptrViEImageProcess->RegisterCaptureEffectFilter( + tbCapture.captureId, effectFilter); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Black and white filter registered for capture device, " + "affects both windows"); + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViEImageProcess->DeregisterCaptureEffectFilter( + tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEImageProcess->RegisterSendEffectFilter( + tbChannel.videoChannel, effectFilter); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Capture filter removed."); + ViETest::Log("Black and white filter registered for one channel, Window2 " + "should be black and white"); + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViEImageProcess->DeregisterSendEffectFilter( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViEImageProcess Standard Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViEImageProcess Standard Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + +int ViEAutoTest::ViEImageProcessExtendedTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEImageProcess Extended Test\n"); + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + numberOfErrors = ViEImageProcessStandardTest(); + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViEImageProcess Extended Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViEImageProcess Extended Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + +int ViEAutoTest::ViEImageProcessAPITest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViEImageProcess API Test\n"); + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + int rtpPort = 6000; + tbInterfaces ViE("ViEImageProcessAPITest", numberOfErrors); + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + tbCaptureDevice tbCapture(ViE, numberOfErrors); + + tbCapture.ConnectTo(tbChannel.videoChannel); + + MyEffectFilter effectFilter; + + // + // Capture effect filter + // + // Add effect filter + error = ViE.ptrViEImageProcess->RegisterCaptureEffectFilter( + tbCapture.captureId, effectFilter); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + // Add again -> error + error = ViE.ptrViEImageProcess->RegisterCaptureEffectFilter( + tbCapture.captureId, effectFilter); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->DeregisterCaptureEffectFilter( + tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + // Double deregister + error = ViE.ptrViEImageProcess->DeregisterCaptureEffectFilter( + tbCapture.captureId); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + // Non-existing capture device + error = ViE.ptrViEImageProcess->RegisterCaptureEffectFilter( + tbChannel.videoChannel, effectFilter); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // Render effect filter + // + error = ViE.ptrViEImageProcess->RegisterRenderEffectFilter( + tbChannel.videoChannel, effectFilter); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->RegisterRenderEffectFilter( + tbChannel.videoChannel, effectFilter); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->DeregisterRenderEffectFilter( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->DeregisterRenderEffectFilter( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + // Non-existing channel id + error = ViE.ptrViEImageProcess->RegisterRenderEffectFilter( + tbCapture.captureId, effectFilter); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // Send effect filter + // + error = ViE.ptrViEImageProcess->RegisterSendEffectFilter( + tbChannel.videoChannel, effectFilter); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->RegisterSendEffectFilter( + tbChannel.videoChannel, effectFilter); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->DeregisterSendEffectFilter( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->DeregisterSendEffectFilter( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->RegisterSendEffectFilter( + tbCapture.captureId, effectFilter); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // Denoising + // + error = ViE.ptrViEImageProcess->EnableDenoising(tbCapture.captureId, true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableDenoising(tbCapture.captureId, true); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableDenoising(tbCapture.captureId, false); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableDenoising(tbCapture.captureId, false); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableDenoising(tbChannel.videoChannel, + true); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // Deflickering + // + error = ViE.ptrViEImageProcess->EnableDeflickering(tbCapture.captureId, + true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableDeflickering(tbCapture.captureId, + true); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableDeflickering(tbCapture.captureId, + false); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableDeflickering(tbCapture.captureId, + false); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableDeflickering(tbChannel.videoChannel, + true); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // Color enhancement + // + error = ViE.ptrViEImageProcess->EnableColorEnhancement( + tbChannel.videoChannel, false); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableColorEnhancement( + tbChannel.videoChannel, true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableColorEnhancement( + tbChannel.videoChannel, true); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableColorEnhancement( + tbChannel.videoChannel, false); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableColorEnhancement( + tbChannel.videoChannel, false); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEImageProcess->EnableColorEnhancement(tbCapture.captureId, + true); + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViEImageProcess Extended Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViEImageProcess Extended Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_linux.cc b/video_engine/main/test/AutoTest/source/vie_autotest_linux.cc new file mode 100644 index 0000000000..8f5f66e656 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_linux.cc @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_linux.cc +// + +#include "vie_autotest_linux.h" + +#include "vie_autotest_defines.h" +#include "vie_autotest_main.h" + +#include "engine_configurations.h" +#include "critical_section_wrapper.h" +#include "thread_wrapper.h" + +ViEAutoTestWindowManager::ViEAutoTestWindowManager() : + _hdsp1(NULL), + _hdsp2(NULL) +{ +} + +ViEAutoTestWindowManager::~ViEAutoTestWindowManager() +{ + TerminateWindows(); +} + +void* ViEAutoTestWindowManager::GetWindow1() +{ + return (void*) _hwnd1; +} + +void* ViEAutoTestWindowManager::GetWindow2() +{ + return (void*) _hwnd2; +} + +int ViEAutoTestWindowManager::TerminateWindows() +{ + if (_hwnd1) + { + ViEDestroyWindow(&_hwnd1, _hdsp1); + } + if (_hwnd2) + { + ViEDestroyWindow(&_hwnd2, _hdsp2); + } + return 0; +} + +int ViEAutoTestWindowManager::CreateWindows(AutoTestRect window1Size, + AutoTestRect window2Size, + void* window1Title, + void* window2Title) +{ + ViECreateWindow(&_hwnd1, &_hdsp1, window1Size.origin.x, + window1Size.origin.y, window1Size.size.width, + window1Size.size.height, (char*) window1Title); + ViECreateWindow(&_hwnd2, &_hdsp2, window2Size.origin.x, + window2Size.origin.y, window2Size.size.width, + window2Size.size.height, (char*) window2Title); + + return 0; +} + +int ViEAutoTestWindowManager::ViECreateWindow(Window *outWindow, + Display **outDisplay, int xpos, + int ypos, int width, int height, + char* title) +{ + int screen; + XEvent evnt; + XSetWindowAttributes xswa; // window attribute struct + XVisualInfo vinfo; // screen visual info struct + unsigned long mask; // attribute mask + + // get connection handle to xserver + Display* _display = XOpenDisplay(NULL); + + // get screen number + screen = DefaultScreen(_display); + + // put desired visual info for the screen in vinfo + // TODO: more display settings should be allowed + if (XMatchVisualInfo(_display, screen, 24, TrueColor, &vinfo) != 0) + { + //printf( "Screen visual info match!\n" ); + } + // set window attributes + xswa.colormap = XCreateColormap(_display, DefaultRootWindow(_display), + vinfo.visual, AllocNone); + xswa.event_mask = StructureNotifyMask | ExposureMask; + xswa.background_pixel = 0; + xswa.border_pixel = 0; + + // value mask for attributes + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + Window _window = XCreateWindow(_display, DefaultRootWindow(_display), xpos, + ypos, width, height, 0, vinfo.depth, + InputOutput, vinfo.visual, mask, &xswa); + + // Set window name + XStoreName(_display, _window, title); + XSetIconName(_display, _window, title); + + // make x report events for mask + XSelectInput(_display, _window, StructureNotifyMask); + + // map the window to the display + XMapWindow(_display, _window); + + // wait for map event + do + { + XNextEvent(_display, &evnt); + + } while (evnt.type != MapNotify || evnt.xmap.event != _window); + + *outWindow = _window; + *outDisplay = _display; + return 0; +} + +int ViEAutoTestWindowManager::ViEDestroyWindow(Window *window, Display *display) +{ + XUnmapWindow(display, *window); + XDestroyWindow(display, *window); + XSync(display, false); + return 0; +} + +bool ViEAutoTestWindowManager::SetTopmostWindow() +{ + return 0; +} + +int main() +{ + ViEAutoTestMain autoTest; + autoTest.UseAnswerFile("answers.txt"); + return autoTest.BeginOSIndependentTesting(); + +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_loopback.cc b/video_engine/main/test/AutoTest/source/vie_autotest_loopback.cc new file mode 100644 index 0000000000..042c564681 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_loopback.cc @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_loopback.cc +// +// This code is also used as sample code for ViE 3.0 +// + +#include "vie_autotest_defines.h" +#include "vie_autotest.h" + +// =================================================================== +// +// BEGIN: VideoEngine 3.0 Sample Code +// + +#include "common_types.h" +#include "voe_base.h" +#include "vie_base.h" +#include "vie_capture.h" +#include "vie_codec.h" +#include "vie_network.h" +#include "vie_render.h" +#include "vie_rtp_rtcp.h" + +int VideoEngineSampleCode(void* window1, void* window2) +{ + //******************************************************** + // Begin create/initialize Video Engine for testing + //******************************************************** + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + // + // Create a VideoEngine instance + // + VideoEngine* ptrViE = NULL; + ptrViE = VideoEngine::Create(); + if (ptrViE == NULL) + { + printf("ERROR in VideoEngine::Create\n"); + return -1; + } + + error = ptrViE->SetTraceFilter(webrtc::kTraceAll); + if (error == -1) + { + printf("ERROR in VideoEngine::SetTraceLevel\n"); + return -1; + } + +#ifdef ANDROID + error = ptrViE->SetTraceFile("/sdcard/ViETrace.txt"); + if (error == -1) + { + printf("ERROR in VideoEngine::SetTraceFile\n"); + return -1; + } + + error = ptrViE->SetTraceFile("/sdcard/ViEEncryptedTrace.txt"); + if (error == -1) + { + printf("ERROR in VideoEngine::SetTraceFile\n"); + return -1; + } +#else + error = ptrViE->SetTraceFile("ViETrace.txt"); + if (error == -1) + { + printf("ERROR in VideoEngine::SetTraceFile\n"); + return -1; + } + +#endif + + // + // Init VideoEngine and create a channel + // + ViEBase* ptrViEBase = ViEBase::GetInterface(ptrViE); + if (ptrViEBase == NULL) + { + printf("ERROR in ViEBase::GetInterface\n"); + return -1; + } + + error = ptrViEBase->Init(); + if (error == -1) + { + printf("ERROR in ViEBase::Init\n"); + return -1; + } + + int videoChannel = -1; + error = ptrViEBase->CreateChannel(videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::CreateChannel\n"); + return -1; + } + + // + // List available capture devices, allocate and connect. + // + ViECapture* ptrViECapture = ViECapture::GetInterface(ptrViE); + if (ptrViEBase == NULL) + { + printf("ERROR in ViECapture::GetInterface\n"); + return -1; + } + + const unsigned int KMaxDeviceNameLength = 128; + const unsigned int KMaxUniqueIdLength = 256; + char deviceName[KMaxDeviceNameLength]; + memset(deviceName, 0, KMaxDeviceNameLength); + char uniqueId[KMaxUniqueIdLength]; + memset(uniqueId, 0, KMaxUniqueIdLength); + + printf("Available capture devices:\n"); + int captureIdx = 0; + for (captureIdx = 0; + captureIdx < ptrViECapture->NumberOfCaptureDevices(); + captureIdx++) + { + memset(deviceName, 0, KMaxDeviceNameLength); + memset(uniqueId, 0, KMaxUniqueIdLength); + + error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName, + KMaxDeviceNameLength, uniqueId, + KMaxUniqueIdLength); + if (error == -1) + { + printf("ERROR in ViECapture::GetCaptureDevice\n"); + return -1; + } + printf("\t %d. %s\n", captureIdx + 1, deviceName); + } + printf("\nChoose capture device: "); +#ifdef ANDROID + captureIdx = 0; + printf("0\n"); +#else + int dummy = scanf("%d", &captureIdx); + getchar(); + captureIdx = captureIdx - 1; // Compensate for idx start at 1. +#endif + error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName, + KMaxDeviceNameLength, uniqueId, + KMaxUniqueIdLength); + if (error == -1) + { + printf("ERROR in ViECapture::GetCaptureDevice\n"); + return -1; + } + + int captureId = 0; + error = ptrViECapture->AllocateCaptureDevice(uniqueId, KMaxUniqueIdLength, + captureId); + if (error == -1) + { + printf("ERROR in ViECapture::AllocateCaptureDevice\n"); + return -1; + } + + error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel); + if (error == -1) + { + printf("ERROR in ViECapture::ConnectCaptureDevice\n"); + return -1; + } + + error = ptrViECapture->StartCapture(captureId); + if (error == -1) + { + printf("ERROR in ViECapture::StartCapture\n"); + return -1; + } + + // + // RTP/RTCP settings + // + ViERTP_RTCP* ptrViERtpRtcp = ViERTP_RTCP::GetInterface(ptrViE); + if (ptrViERtpRtcp == NULL) + { + printf("ERROR in ViERTP_RTCP::GetInterface\n"); + return -1; + } + + error = ptrViERtpRtcp->SetRTCPStatus(videoChannel, kRtcpCompound_RFC4585); + if (error == -1) + { + printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n"); + return -1; + } + + error = ptrViERtpRtcp->SetKeyFrameRequestMethod(videoChannel, + kViEKeyFrameRequestPliRtcp); + if (error == -1) + { + printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n"); + return -1; + } + + error = ptrViERtpRtcp->SetTMMBRStatus(videoChannel, true); + if (error == -1) + { + printf("ERROR in ViERTP_RTCP::SetTMMBRStatus\n"); + return -1; + } + + // + // Set up rendering + // + ViERender* ptrViERender = ViERender::GetInterface(ptrViE); + if (ptrViERender == NULL) + { + printf("ERROR in ViERender::GetInterface\n"); + return -1; + } + + error + = ptrViERender->AddRenderer(captureId, window1, 0, 0.0, 0.0, 1.0, 1.0); + if (error == -1) + { + printf("ERROR in ViERender::AddRenderer\n"); + return -1; + } + + error = ptrViERender->StartRender(captureId); + if (error == -1) + { + printf("ERROR in ViERender::StartRender\n"); + return -1; + } + + error = ptrViERender->AddRenderer(videoChannel, window2, 1, 0.0, 0.0, 1.0, + 1.0); + if (error == -1) + { + printf("ERROR in ViERender::AddRenderer\n"); + return -1; + } + + error = ptrViERender->StartRender(videoChannel); + if (error == -1) + { + printf("ERROR in ViERender::StartRender\n"); + return -1; + } + + // + // Setup codecs + // + ViECodec* ptrViECodec = ViECodec::GetInterface(ptrViE); + if (ptrViECodec == NULL) + { + printf("ERROR in ViECodec::GetInterface\n"); + return -1; + } + + // Check available codecs and prepare receive codecs + printf("\nAvailable codecs:\n"); + webrtc::VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + int codecIdx = 0; + for (codecIdx = 0; codecIdx < ptrViECodec->NumberOfCodecs(); codecIdx++) + { + error = ptrViECodec->GetCodec(codecIdx, videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::GetCodec\n"); + return -1; + } + + // try to keep the test frame size small when I420 + if (videoCodec.codecType == webrtc::kVideoCodecI420) + { + videoCodec.width = 176; + videoCodec.height = 144; + } + + error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::SetReceiveCodec\n"); + return -1; + } + if (videoCodec.codecType != webrtc::kVideoCodecRED + && videoCodec.codecType != webrtc::kVideoCodecULPFEC) + { + printf("\t %d. %s\n", codecIdx + 1, videoCodec.plName); + } + } + printf("Choose codec: "); +#ifdef ANDROID + codecIdx = 0; + printf("0\n"); +#else + dummy = scanf("%d", &codecIdx); + getchar(); + codecIdx = codecIdx - 1; // Compensate for idx start at 1. +#endif + + error = ptrViECodec->GetCodec(codecIdx, videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::GetCodec\n"); + return -1; + } + + // try to keep the test frame size small when I420 + if (videoCodec.codecType == webrtc::kVideoCodecI420) + { + videoCodec.width = 176; + videoCodec.height = 144; + } + + error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::SetSendCodec\n"); + return -1; + } + + // + // Address settings + // + ViENetwork* ptrViENetwork = ViENetwork::GetInterface(ptrViE); + if (ptrViENetwork == NULL) + { + printf("ERROR in ViENetwork::GetInterface\n"); + return -1; + } + + const char* ipAddress = "127.0.0.1"; + const unsigned short rtpPort = 6000; + error = ptrViENetwork->SetLocalReceiver(videoChannel, rtpPort); + if (error == -1) + { + printf("ERROR in ViENetwork::SetLocalReceiver\n"); + return -1; + } + + error = ptrViEBase->StartReceive(videoChannel); + if (error == -1) + { + printf("ERROR in ViENetwork::StartReceive\n"); + return -1; + } + + error = ptrViENetwork->SetSendDestination(videoChannel, ipAddress, rtpPort); + if (error == -1) + { + printf("ERROR in ViENetwork::SetSendDestination\n"); + return -1; + } + + error = ptrViEBase->StartSend(videoChannel); + if (error == -1) + { + printf("ERROR in ViENetwork::StartSend\n"); + return -1; + } + + //******************************************************** + // Engine started + //******************************************************** + + + // Call started + printf("\nLoopback call started\n\n"); + printf("Press enter to stop..."); + while ((getchar()) != '\n') + ; + + //******************************************************** + // Testing finished. Tear down Video Engine + //******************************************************** + + error = ptrViEBase->StopReceive(videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::StopReceive\n"); + return -1; + } + + error = ptrViEBase->StopSend(videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::StopSend\n"); + return -1; + } + + error = ptrViERender->StopRender(captureId); + if (error == -1) + { + printf("ERROR in ViERender::StopRender\n"); + return -1; + } + + error = ptrViERender->RemoveRenderer(captureId); + if (error == -1) + { + printf("ERROR in ViERender::RemoveRenderer\n"); + return -1; + } + + error = ptrViERender->StopRender(videoChannel); + if (error == -1) + { + printf("ERROR in ViERender::StopRender\n"); + return -1; + } + + error = ptrViERender->RemoveRenderer(videoChannel); + if (error == -1) + { + printf("ERROR in ViERender::RemoveRenderer\n"); + return -1; + } + + error = ptrViECapture->StopCapture(captureId); + if (error == -1) + { + printf("ERROR in ViECapture::StopCapture\n"); + return -1; + } + + error = ptrViECapture->DisconnectCaptureDevice(videoChannel); + if (error == -1) + { + printf("ERROR in ViECapture::DisconnectCaptureDevice\n"); + return -1; + } + + error = ptrViECapture->ReleaseCaptureDevice(captureId); + if (error == -1) + { + printf("ERROR in ViECapture::ReleaseCaptureDevice\n"); + return -1; + } + + error = ptrViEBase->DeleteChannel(videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::DeleteChannel\n"); + return -1; + } + + int remainingInterfaces = 0; + remainingInterfaces = ptrViECodec->Release(); + remainingInterfaces += ptrViECapture->Release(); + remainingInterfaces += ptrViERtpRtcp->Release(); + remainingInterfaces += ptrViERender->Release(); + remainingInterfaces += ptrViENetwork->Release(); + remainingInterfaces += ptrViEBase->Release(); + if (remainingInterfaces > 0) + { + printf("ERROR: Could not release all interfaces\n"); + return -1; + } + + bool deleted = VideoEngine::Delete(ptrViE); + if (deleted == false) + { + printf("ERROR in VideoEngine::Delete\n"); + return -1; + } + + return 0; + + // + // END: VideoEngine 3.0 Sample Code + // + // =================================================================== +} + +int ViEAutoTest::ViELoopbackCall() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViE Autotest Loopback Call\n"); + + if (VideoEngineSampleCode(_window1, _window2) == 0) + { + ViETest::Log(" "); + ViETest::Log(" ViE Autotest Loopback Call Done"); + ViETest::Log("========================================"); + ViETest::Log(" "); + + return 0; + } + + ViETest::Log(" "); + ViETest::Log(" ViE Autotest Loopback Call Failed"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 1; + +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_mac_carbon.cc b/video_engine/main/test/AutoTest/source/vie_autotest_mac_carbon.cc new file mode 100644 index 0000000000..b07cbe5d48 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_mac_carbon.cc @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_autotest_mac_carbon.cc + * + */ + +#include "engine_configurations.h" + +#if defined(CARBON_RENDERING) +#include "vie_autotest_mac_carbon.h" +#include "vie_autotest_defines.h" +#include "vie_autotest.h" +#include "vie_autotest_main.h" + +ViEAutoTestWindowManager::ViEAutoTestWindowManager() : + _carbonWindow1(new WindowRef()), + _carbonWindow2(new WindowRef()), + _hiView1(new HIViewRef()), + _hiView2(new HIViewRef()) +{ +} + +ViEAutoTestWindowManager::~ViEAutoTestWindowManager() +{ + if (_carbonWindow1EventHandlerRef) + RemoveEventHandler(_carbonWindow1EventHandlerRef); + + if (_carbonWindow2EventHandlerRef) + RemoveEventHandler(_carbonWindow2EventHandlerRef); + + if (_carbonHIView1EventHandlerRef) + RemoveEventHandler(_carbonHIView1EventHandlerRef); + + if (_carbonHIView2EventHandlerRef) + RemoveEventHandler(_carbonHIView2EventHandlerRef); + + delete _carbonWindow1; + delete _carbonWindow2; + delete _hiView1; + delete _hiView2; +} + +int ViEAutoTestWindowManager::CreateWindows(AutoTestRect window1Size, + AutoTestRect window2Size, + char* window1Title, + char* window2Title) +{ + + WindowAttributes windowAttributes = kWindowStandardDocumentAttributes + | kWindowStandardHandlerAttribute | kWindowCompositingAttribute; + Rect windowContentRect; + static const EventTypeSpec + windowEventTypes[] = { kEventClassWindow, kEventWindowBoundsChanged, + kEventClassWindow, kEventWindowBoundsChanging, kEventClassWindow, + kEventWindowZoomed, kEventClassWindow, kEventWindowExpanded, + kEventClassWindow, kEventWindowClickResizeRgn, kEventClassWindow, + kEventWindowClickDragRgn }; + + // ************* Window 1 and Event Handler *********************** + + SetRect(&windowContentRect, window1Size.origin.x, window1Size.origin.y, + window1Size.origin.x + window1Size.size.width, window1Size.origin.y + + window1Size.size.height); + + CreateNewWindow(kDocumentWindowClass, windowAttributes, &windowContentRect, + _carbonWindow1); + SetWindowTitleWithCFString(*_carbonWindow1, CFSTR("Carbon Window 1")); + ShowWindow(*_carbonWindow1); + InitCursor(); + InstallWindowEventHandler(*_carbonWindow1, + NewEventHandlerUPP(HandleWindowEvent), + GetEventTypeCount(windowEventTypes), + windowEventTypes, (void*) this, + &_carbonWindow1EventHandlerRef); + + // ************* Window 2 and Event Handler *********************** + + SetRect(&windowContentRect, window2Size.origin.x, window2Size.origin.y, + window2Size.origin.x + window2Size.size.width, window2Size.origin.y + + window2Size.size.height); + + CreateNewWindow(kDocumentWindowClass, windowAttributes, &windowContentRect, + _carbonWindow2); + SetWindowTitleWithCFString(*_carbonWindow2, CFSTR("Carbon Window 2")); + ShowWindow(*_carbonWindow2); + InitCursor(); + InstallWindowEventHandler(*_carbonWindow2, + NewEventHandlerUPP(HandleWindowEvent), + GetEventTypeCount(windowEventTypes), + windowEventTypes, (void*) this, + &_carbonWindow2EventHandlerRef); + +#if defined(HIVIEWREF_MODE) + OSStatus status; + static const EventTypeSpec hiviewEventTypes[] = { kEventClassControl, + kEventControlBoundsChanged, kEventClassControl, kEventControlDraw }; + + HIRect hiView1Rect = { 10, 10, 200, 200 }; + status = HICreateCustomView(&hiView1Rect, &_hiView1); + status = HIViewAddSubview(&_carbonWindow1, _hiView1); + HIViewSetZOrder(_hiView1, kHIViewZOrderAbove, NULL); + HIViewSetVisible(_hiView1, true); + + HIViewInstallEventHandler(_hiView1, NewEventHandlerUPP(HandleHIViewEvent), + GetEventTypeCount(hiviewEventTypes), + hiviewEventTypes, (void *) this, + &_carbonHIView1EventHandlerRef); + + HIRect hiView2Rect = { 10, 10, 200, 200 }; + status = HICreateCustomView(&hiView2Rect, &_hiView2); + status = HIViewAddSubview(&_carbonWindow2, _hiView2); + HIViewSetZOrder(_hiView2, kHIViewZOrderAbove, NULL); + HIViewSetVisible(_hiView2, true); + + HIViewInstallEventHandler(_hiView2, NewEventHandlerUPP(HandleHIViewEvent), + GetEventTypeCount(hiviewEventTypes), + hiviewEventTypes, (void *) this, + &_carbonHIView2EventHandlerRef); +#endif + + return 0; +} + +pascal OSStatus ViEAutoTestWindowManager::HandleWindowEvent( + EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) +{ + + WindowRef windowRef = NULL; + + int eventType = GetEventKind(theEvent); + + // see https://dcs.sourcerepo.com/dcs/tox_view/trunk/tox/libraries/ + // i686-win32/include/quicktime/CarbonEvents.h for a list of codes + GetEventParameter(theEvent, kEventParamDirectObject, typeWindowRef, NULL, + sizeof(WindowRef), NULL, &windowRef); + + ViEAutoTestWindowManager* obj = (ViEAutoTestWindowManager*) (userData); + + if (windowRef == obj->GetWindow1()) + { + // event was triggered on window 1 + } + else if (windowRef == obj->GetWindow2()) + { + // event was triggered on window 2 + } + + if (kEventWindowBoundsChanged == eventType) + { + } + else if (kEventWindowBoundsChanging == eventType) + { + } + else if (kEventWindowZoomed == eventType) + { + } + else if (kEventWindowExpanding == eventType) + { + } + else if (kEventWindowExpanded == eventType) + { + } + else if (kEventWindowClickResizeRgn == eventType) + { + } + else if (kEventWindowClickDragRgn == eventType) + { + } + else + { + } + + return noErr; +} + +pascal OSStatus ViEAutoTestWindowManager::HandleHIViewEvent( + EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) +{ + HIViewRef hiviewRef = NULL; + + // see https://dcs.sourcerepo.com/dcs/tox_view/trunk/tox/libraries/ + // i686-win32/include/quicktime/CarbonEvents.h for a list of codes + int eventType = GetEventKind(theEvent); + OSStatus status = noErr; + status = GetEventParameter(theEvent, kEventParamDirectObject, + typeControlRef, NULL, sizeof(ControlRef), NULL, + &hiviewRef); + + if (GetEventClass(theEvent) == kEventClassControl) + { + if (GetEventKind(theEvent) == kEventControlDraw) + { + ViEAutoTestWindowManager* obj = + (ViEAutoTestWindowManager*) (userData); + + CGContextRef context; + status = GetEventParameter(theEvent, kEventParamCGContextRef, + typeCGContextRef, NULL, sizeof(context), + NULL, &context); + HIRect viewBounds; + + HIViewRef* ptrHIViewRef = + static_cast (obj->GetWindow1()); + if (hiviewRef == *ptrHIViewRef) + { + // color hiview1 + CGContextSetRGBFillColor(context, 1, 0, 0, 1); + HIViewGetBounds(hiviewRef, &viewBounds); + CGContextFillRect(context, viewBounds); + } + + ptrHIViewRef = static_cast (obj->GetWindow1()); + if (hiviewRef == *ptrHIViewRef) + { + CGContextSetRGBFillColor(context, 0, 1, 0, 1); + HIViewGetBounds(hiviewRef, &viewBounds); + CGContextFillRect(context, viewBounds); + } + + } + } + + /* + + + VideoRenderAGL* obj = (VideoRenderAGL*)(userData); + WindowRef parentWindow = HIViewGetWindow(hiviewRef); + bool updateUI = true; + + if(kEventControlBoundsChanged == eventType){ + } + else if(kEventControlDraw == eventType){ + } + else{ + updateUI = false; + } + + if(true == updateUI){ + obj->ParentWindowResized(parentWindow); + obj->UpdateClipping(); + obj->RenderOffScreenBuffers(); + } + */ + + return status; +} + +int ViEAutoTestWindowManager::TerminateWindows() +{ + return 0; +} + +void* ViEAutoTestWindowManager::GetWindow1() +{ +#if defined(HIVIEWREF_MODE) + return (void*)_hiView1; +#else + return (void*) _carbonWindow1; +#endif + +} +void* ViEAutoTestWindowManager::GetWindow2() +{ +#if defined(HIVIEWREF_MODE) + return (void*)_hiView2; +#else + return (void*) _carbonWindow2; +#endif + +} + +bool ViEAutoTestWindowManager::SetTopmostWindow() +{ + return true; +} + +/* + + int main (int argc, const char * argv[]) + { + ViEAutoTestMain autoTest; + + if(argc > 1){ + autoTest.UseAnswerFile(argv[1]); + } + + int success = autoTest.BeginOSIndependentTesting(); + + } + + */ + +int main(int argc, const char * argv[]) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + [NSApplication sharedApplication]; + + // we have to run the test in a secondary thread because we need to run a runloop, which blocks + if (argc > 1) + { +AutoTestClass * autoTestClass = [[AutoTestClass alloc]init]; + [NSThread detachNewThreadSelector:@selector(autoTestWithArg:) + toTarget:autoTestClass withObject:[NSString stringWithFormat:@"%s", + argv[1]]]; +} +else +{ + AutoTestClass* autoTestClass = [[AutoTestClass alloc]init]; + [NSThread detachNewThreadSelector:@selector(autoTestWithArg:) + toTarget:autoTestClass withObject:nil]; +} + +// process OS events. Blocking call +[[NSRunLoop currentRunLoop]run]; +[pool release]; +} + +@implementation AutoTestClass + +-(void)autoTestWithArg:(NSString*)answerFile; +{ + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + ViEAutoTestMain autoTest; + + if(NSOrderedSame != [answerFile compare:@""]) + { + char answerFileUTF8[1024] = ""; + strcpy(answerFileUTF8, (char*)[answerFileUTF8 UTF8]); + autoTest.UseAnswerFile(answerFileUTF8); + } + + int success = autoTest.BeginOSIndependentTesting(); + + [pool release]; + return; +} +// TODO: move window creation to Obj-c class so GUI commands can be run on the +// main NSThread +// -(void)createWindow1:(AutoTestRect)window1Size +// AndWindow2:(AutoTestRect)window2Size WithTitle1:(char*)window1Title +// AndTitle2:(char*)window2Title{ + +@end + +#endif + diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_mac_cocoa.cc b/video_engine/main/test/AutoTest/source/vie_autotest_mac_cocoa.cc new file mode 100644 index 0000000000..df9290eab9 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_mac_cocoa.cc @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "engine_configurations.h" + +#if defined(COCOA_RENDERING) +#include "vie_autotest_mac_cocoa.h" +#include "vie_autotest_defines.h" +#include "vie_autotest.h" +#include "vie_autotest_main.h" + +ViEAutoTestWindowManager::ViEAutoTestWindowManager() : + _cocoaRenderView1(nil), _cocoaRenderView2(nil) +{ + +} + +ViEAutoTestWindowManager::~ViEAutoTestWindowManager() +{ + if (_cocoaRenderView1) + { + [ _cocoaRenderView1 release]; + } + if(_cocoaRenderView2) + { + [_cocoaRenderView2 release]; + } +} + +int ViEAutoTestWindowManager::CreateWindows(AutoTestRect window1Size, + AutoTestRect window2Size, + void* window1Title, + void* window2Title) +{ + NSRect outWindow1Frame = NSMakeRect(window1Size.origin.x, + window1Size.origin.y, + window1Size.size.width, + window1Size.size.height); + NSWindow* outWindow1 = [[NSWindow alloc] initWithContentRect:outWindow1Frame + styleMask:NSTitledWindowMask + backing:NSBackingStoreBuffered defer:NO]; + [outWindow1 orderOut:nil]; + NSRect cocoaRenderView1Frame = NSMakeRect(0, 0, window1Size.size.width, + window1Size.size.height); + _cocoaRenderView1 = [[CocoaRenderView alloc] + initWithFrame:cocoaRenderView1Frame]; + [[outWindow1 contentView] addSubview:_cocoaRenderView1]; + [outWindow1 setTitle:[NSString stringWithFormat:@"%s", window1Title]]; + [outWindow1 makeKeyAndOrderFront:NSApp]; + + NSRect outWindow2Frame = NSMakeRect(window2Size.origin.x, + window2Size.origin.y, + window2Size.size.width, + window2Size.size.height); + NSWindow* outWindow2 = [[NSWindow alloc] initWithContentRect:outWindow2Frame + styleMask:NSTitledWindowMask + backing:NSBackingStoreBuffered defer:NO]; + [outWindow2 orderOut:nil]; + NSRect cocoaRenderView2Frame = NSMakeRect(0, 0, window2Size.size.width, + window2Size.size.height); + _cocoaRenderView2 = [[CocoaRenderView alloc] + initWithFrame:cocoaRenderView2Frame]; + [[outWindow2 contentView] addSubview:_cocoaRenderView2]; + [outWindow2 setTitle:[NSString stringWithFormat:@"%s", window2Title]]; + [outWindow2 makeKeyAndOrderFront:NSApp]; + + return 0; +} + +int ViEAutoTestWindowManager::TerminateWindows() +{ + return 0; +} + +void* ViEAutoTestWindowManager::GetWindow1() +{ + return _cocoaRenderView1; +} + +void* ViEAutoTestWindowManager::GetWindow2() +{ + return _cocoaRenderView2; +} + +bool ViEAutoTestWindowManager::SetTopmostWindow() +{ + return true; +} + +int main(int argc, const char * argv[]) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + [NSApplication sharedApplication]; + +#if defined(MAC_COCOA_USE_NSRUNLOOP) + // we have to run the test in a secondary thread because we need to run a + // runloop, which blocks + if (argc > 1) + { + AutoTestClass * autoTestClass = [[AutoTestClass alloc]init]; + [NSThread detachNewThreadSelector:@selector(autoTestWithArg:) + toTarget:autoTestClass withObject:[NSString stringWithFormat:@"%s", + argv[1]]]; + } + else + { + AutoTestClass* autoTestClass = [[AutoTestClass alloc]init]; + [NSThread detachNewThreadSelector:@selector(autoTestWithArg:) + toTarget:autoTestClass withObject:nil]; + } + +// process OS events. Blocking call +[[NSRunLoop mainRunLoop]run]; + +#else + + ViEAutoTestMain autoTest; + int success = autoTest.BeginOSIndependentTesting(); +#endif +[pool release]; +} + +@implementation AutoTestClass + +-(void)autoTestWithArg:(NSString*)answerFile; +{ + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + ViEAutoTestMain autoTest; + + if(NSOrderedSame != [answerFile compare:@""]) + { + char answerFileUTF8[1024] = ""; + strcpy(answerFileUTF8, (char*)[answerFileUTF8 UTF8]); + autoTest.UseAnswerFile(answerFileUTF8); + } + + int success = autoTest.BeginOSIndependentTesting(); + + [pool release]; + return; +} + +@end + +#endif + diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_main.cc b/video_engine/main/test/AutoTest/source/vie_autotest_main.cc new file mode 100644 index 0000000000..df1c262f0a --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_main.cc @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * vie_autotest_main.cc + * + */ + +#include "vie_autotest.h" +#include "vie_autotest_defines.h" +#include "vie_autotest_main.h" +#include "vie_codec.h" +#include "voe_codec.h" + +#if defined(WIN32) + #include "vie_autotest_windows.h" + #include + #include //ShellExecute +#elif defined(WEBRTC_MAC_INTEL) + #if defined(COCOA_RENDERING) + #include "vie_autotest_mac_cocoa.h" +#elif defined(CARBON_RENDERING) + #include "vie_autotest_mac_carbon.h" +#endif +#elif defined(WEBRTC_LINUX) + #include "vie_autotest_linux.h" +#endif + +ViEAutoTestMain::ViEAutoTestMain() : + _answers(), + _answersCount(0), + _useAnswerFile() +{ +} + +bool ViEAutoTestMain::BeginOSIndependentTesting() +{ + // Create platform dependent render windows + ViEAutoTestWindowManagerInterface* windowManager = + new ViEAutoTestWindowManager(); + +#if (defined(_WIN32)) + TCHAR window1Title[1024] = _T("ViE Autotest Window 1"); + TCHAR window2Title[1024] = _T("ViE Autotest Window 2"); +#else + char window1Title[1024] = "ViE Autotest Window 1"; + char window2Title[1024] = "ViE Autotest Window 2"; +#endif + + AutoTestRect window1Size(352, 288, 600, 100); + AutoTestRect window2Size(352, 288, 1000, 100); + windowManager->CreateWindows(window1Size, window2Size, window1Title, + window2Title); + windowManager->SetTopmostWindow(); + + // Create the test cases + ViEAutoTest vieAutoTest(windowManager->GetWindow1(), + windowManager->GetWindow2()); + + ViETest::Log(" ============================== "); + ViETest::Log(" WebRTC ViE 3.x Autotest "); + ViETest::Log(" ============================== \n"); + + int testType = 0; + int testErrors = 0; + do + { + ViETest::Log("Test types: "); + ViETest::Log("\t 0. Quit"); + ViETest::Log("\t 1. All standard tests (delivery test)"); + ViETest::Log("\t 2. All API tests"); + ViETest::Log("\t 3. All extended test"); + ViETest::Log("\t 4. Specific standard test"); + ViETest::Log("\t 5. Specific API test"); + ViETest::Log("\t 6. Specific extended test"); + ViETest::Log("\t 7. Simple loopback call"); + ViETest::Log("\t 8. Custom configure a call"); + ViETest::Log("Select type of test: "); + + if (_useAnswerFile) + { + //GetNextAnswer(str); + } + else + { + int dummy = scanf("%d", &testType); + getchar(); + } + ViETest::Log(""); + + if (testType < 1 && testType > 7) + { + ViETest::Log("ERROR: Invalid selection. Try again"); + continue; + } + + switch (testType) + { + case 0: + break; + + case 1: + { + int deliveryErrors = testErrors; + testErrors += vieAutoTest.ViEStandardTest(); + if (testErrors == deliveryErrors) + { + // No errors found in delivery test, create delivery + ViETest::Log("Standard/delivery passed."); + } + else + { + // Didn't pass, don't create delivery files + ViETest::Log("\nStandard/delivery test failed!\n"); + } + break; + } + case 2: + testErrors += vieAutoTest.ViEAPITest(); + break; + + case 3: + testErrors += vieAutoTest.ViEExtendedTest(); + break; + + case 4: // specific Standard + testType = GetClassTestSelection(); + + switch (testType) + { + case 1: // base + testErrors += vieAutoTest.ViEBaseStandardTest(); + break; + + case 2: // capture + testErrors += vieAutoTest.ViECaptureStandardTest(); + break; + + case 3: // codec + testErrors += vieAutoTest.ViECodecStandardTest(); + break; + + case 5: //encryption + testErrors += vieAutoTest.ViEEncryptionStandardTest(); + break; + + case 6: // file + testErrors += vieAutoTest.ViEFileStandardTest(); + break; + + case 7: // image process + testErrors += vieAutoTest.ViEImageProcessStandardTest(); + break; + + case 8: // network + testErrors += vieAutoTest.ViENetworkStandardTest(); + break; + + case 9: // Render + testErrors += vieAutoTest.ViERenderStandardTest(); + break; + + case 10: // RTP/RTCP + testErrors += vieAutoTest.ViERtpRtcpStandardTest(); + break; + case 11: + break; + + default: + break; + } + break; + + case 5: // specific API + testType = GetClassTestSelection(); + + switch (testType) + { + case 1: // base + testErrors += vieAutoTest.ViEBaseAPITest(); + break; + + case 2: // capture + testErrors += vieAutoTest.ViECaptureAPITest(); + break; + + case 3: // codec + testErrors += vieAutoTest.ViECodecAPITest(); + break; + + case 5: //encryption + testErrors += vieAutoTest.ViEEncryptionAPITest(); + break; + + case 6: // file + testErrors += vieAutoTest.ViEFileAPITest(); + break; + + case 7: // image process + testErrors += vieAutoTest.ViEImageProcessAPITest(); + break; + + case 8: // network + testErrors += vieAutoTest.ViENetworkAPITest(); + break; + + case 9: // Render + testErrors += vieAutoTest.ViERenderAPITest(); + break; + + case 10: // RTP/RTCP + testErrors += vieAutoTest.ViERtpRtcpAPITest(); + break; + case 11: + break; + + default: + break; + } + break; + case 6: // specific extended + testType = GetClassTestSelection(); + + switch (testType) + { + case 1: // base + testErrors += vieAutoTest.ViEBaseExtendedTest(); + break; + + case 2: // capture + testErrors += vieAutoTest.ViECaptureExtendedTest(); + break; + + case 3: // codec + testErrors += vieAutoTest.ViECodecExtendedTest(); + break; + + case 5: //encryption + testErrors += vieAutoTest.ViEEncryptionExtendedTest(); + break; + + case 6: // file + testErrors += vieAutoTest.ViEFileExtendedTest(); + break; + + case 7: // image process + testErrors += vieAutoTest.ViEImageProcessExtendedTest(); + break; + + case 8: // network + testErrors += vieAutoTest.ViENetworkExtendedTest(); + break; + + case 9: // Render + testErrors += vieAutoTest.ViERenderExtendedTest(); + break; + + case 10: // RTP/RTCP + testErrors += vieAutoTest.ViERtpRtcpExtendedTest(); + break; + case 11: + break; + + default: + break; + } + break; + case 7: + testErrors += vieAutoTest.ViELoopbackCall(); + break; + case 8: + testErrors += vieAutoTest.ViECustomCall(); + break; + default: + break; + } + } while (testType != 0); + + windowManager->TerminateWindows(); + + if (testErrors) + { + ViETest::Log("Test done with errors, see ViEAutotestLog.txt for test " + "result.\n"); + } + else + { + ViETest::Log("Test done without errors, see ViEAutotestLog.txt for " + "test result.\n"); + } + printf("Press enter to quit..."); + char c; + while ((c = getchar()) != '\n' && c != EOF) + /* discard */; + + delete windowManager; + + return true; +} + +int ViEAutoTestMain::GetClassTestSelection() +{ + int testType = 0; + std::string answer; + int dummy = 0; + while (1) + { + ViETest::Log("Choose specific test: "); + ViETest::Log("\t 1. Base "); + ViETest::Log("\t 2. Capture"); + ViETest::Log("\t 3. Codec"); + ViETest::Log("\t 5. Encryption"); + ViETest::Log("\t 6. File"); + ViETest::Log("\t 7. Image Process"); + ViETest::Log("\t 8. Network"); + ViETest::Log("\t 9. Render"); + ViETest::Log("\t 10. RTP/RTCP"); + ViETest::Log("\t 11. Go back to previous menu"); + ViETest::Log("Select type of test: "); + + if (_useAnswerFile) + { + //GetNextAnswer(answer); + } + else + { + dummy = scanf("%d", &testType); + getchar(); + } + ViETest::Log("\n"); + if (testType >= 1 && testType <= 13) + { + return testType; + } + ViETest::Log("ERROR: Invalid selection. Try again"); + } + + return -1; +} + +bool ViEAutoTestMain::GetAnswer(int index, string& answer) +{ + if (!_useAnswerFile || index > _answersCount) + { + return false; + } + answer = _answers[index]; + return true; +} + +bool ViEAutoTestMain::IsUsingAnswerFile() +{ + + return _useAnswerFile; +} + +// TODO: write without stl +bool ViEAutoTestMain::UseAnswerFile(const char* fileName) +{ + return false; + /* + _useAnswerFile = false; + + ViETest::Log("Opening answer file: %s...", fileName); + + ifstream answerFile(fileName); + if(!answerFile) + { + ViETest::Log("failed! X(\n"); + return false; + } + + _answersCount = 1; + _answersIndex = 1; + char lineContent[128] = ""; + while(!answerFile.eof()) + { + answerFile.getline(lineContent, 128); + _answers[_answersCount++] = string(lineContent); + } + answerFile.close(); + + cout << "Success :)" << endl << endl; + + _useAnswerFile = true; + + return _useAnswerFile; + */ +} + + diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_network.cc b/video_engine/main/test/AutoTest/source/vie_autotest_network.cc new file mode 100644 index 0000000000..9605913022 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_network.cc @@ -0,0 +1,1058 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_network.cc +// + +#include "vie_autotest_defines.h" +#include "vie_autotest.h" +#include "engine_configurations.h" + +#include "tb_capture_device.h" +#include "tb_external_transport.h" +#include "tb_interfaces.h" +#include "tb_video_channel.h" + +#if defined(_WIN32) +#include +#elif defined(WEBRTC_MAC_INTEL) + +#endif + +class ViEAutoTestNetworkObserver: public ViENetworkObserver +{ +public: + ViEAutoTestNetworkObserver() + { + } + ~ViEAutoTestNetworkObserver() + { + } + virtual void OnPeriodicDeadOrAlive(const int videoChannel, const bool alive) + { + } + virtual void PacketTimeout(const int videoChannel, + const ViEPacketTimeout timeout) + { + } +}; + +int ViEAutoTest::ViENetworkStandardTest() +{ + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + tbInterfaces ViE("ViENetworkStandardTest", numberOfErrors); // Create VIE + tbCaptureDevice tbCapture(ViE, numberOfErrors); + error = ViE.ptrViERender->AddRenderer(tbCapture.captureId, _window1, 0, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + { + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + tbCapture.ConnectTo(tbChannel.videoChannel); + + error = ViE.ptrViERender->AddRenderer(tbChannel.videoChannel, _window2, + 1, 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + + // + // Transport + // + tbExternalTransport testTransport(*ViE.ptrViENetwork); + error = ViE.ptrViENetwork->RegisterSendTransport(tbChannel.videoChannel, + testTransport); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error= ViE.ptrViERtpRtcp->SetKeyFrameRequestMethod(tbChannel.videoChannel, + kViEKeyFrameRequestPliRtcp); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Call started using external transport, video should " + "see video in both windows\n"); + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViEBase->StopReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->DeregisterSendTransport( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + char myIpAddress[64]; + memset(myIpAddress, 0, 64); + unsigned short rtpPort = 1234; + memcpy(myIpAddress, "127.0.0.1", sizeof("127.0.0.1")); + error = ViE.ptrViENetwork->SetLocalReceiver(tbChannel.videoChannel, + rtpPort, rtpPort + 1, + myIpAddress); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendDestination(tbChannel.videoChannel, + myIpAddress, rtpPort, + rtpPort + 1, rtpPort); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Changed to WebRTC SocketTransport, you should still see " + "video in both windows\n"); + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViENetwork->SetSourceFilter(tbChannel.videoChannel, + rtpPort + 10, rtpPort + 11, + myIpAddress); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("Added UDP port filter for incorrect ports, you should " + "not see video in Window2"); + AutoTestSleep(2000); + error = ViE.ptrViENetwork->SetSourceFilter(tbChannel.videoChannel, + rtpPort, rtpPort + 1, + "123.1.1.0"); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("Added IP filter for incorrect IP address, you should not " + "see video in Window2"); + AutoTestSleep(2000); + error = ViE.ptrViENetwork->SetSourceFilter(tbChannel.videoChannel, + rtpPort, rtpPort + 1, + myIpAddress); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log("Added IP filter for this computer, you should see video " + "in Window2 again\n"); + AutoTestSleep(KAutoTestSleepTimeMs); + + tbCapture.Disconnect(tbChannel.videoChannel); + } + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViENetwork Standard Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViENetwork Standard Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + +int ViEAutoTest::ViENetworkExtendedTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViENetwork Extended Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + int numberOfErrors = ViENetworkStandardTest(); + + int error = 0; + bool succeeded = true; + + tbInterfaces ViE("ViENetworkExtendedTest", numberOfErrors); // Create VIE + tbCaptureDevice tbCapture(ViE, numberOfErrors); + error = ViE.ptrViERender->AddRenderer(tbCapture.captureId, _window1, 0, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + { + // + // ToS + // + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + tbCapture.ConnectTo(tbChannel.videoChannel); + char* remoteIp = "192.168.200.1"; + int DSCP = 0; + bool useSetSockOpt = false; + + webrtc::VideoCodec videoCodec; + error = ViE.ptrViECodec->GetSendCodec(tbChannel.videoChannel, + videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + videoCodec.maxFramerate = 5; + error = ViE.ptrViECodec->SetSendCodec(tbChannel.videoChannel, + videoCodec); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + char myIpAddress[64]; + memset(myIpAddress, 0, 64); + unsigned short rtpPort = 9000; + error = ViE.ptrViENetwork->GetLocalIP(myIpAddress, false); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetLocalReceiver(tbChannel.videoChannel, + rtpPort, rtpPort + 1, + myIpAddress); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendDestination(tbChannel.videoChannel, + remoteIp, rtpPort, + rtpPort + 1, rtpPort); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // ToS + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, 2); + if (error != 0) + { + ViETest::Log("ViESetSendToS error!."); + ViETest::Log("You must be admin to run these tests."); + ViETest::Log("On Win7 and late Vista, you need to right click the " + "exe and choose"); + ViETest::Log("\"Run as administrator\"\n"); + int dummyChar = getchar(); + } + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendToS(tbChannel.videoChannel, DSCP, + useSetSockOpt); // No ToS set + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Use Wireshark to capture the outgoing video stream and " + "verify ToS settings\n"); + ViETest::Log(" DSCP set to 0x%x\n", DSCP); + AutoTestSleep(1000); + + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, 63); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendToS(tbChannel.videoChannel, DSCP, + useSetSockOpt); // No ToS set + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log(" DSCP set to 0x%x\n", DSCP); + AutoTestSleep(1000); + + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, 0); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, 2, true); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendToS(tbChannel.videoChannel, DSCP, + useSetSockOpt); // No ToS set + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log(" DSCP set to 0x%x\n", DSCP); + AutoTestSleep(1000); + + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, 63, true); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendToS(tbChannel.videoChannel, DSCP, + useSetSockOpt); // No ToS set + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + ViETest::Log(" DSCP set to 0x%x\n", DSCP); + AutoTestSleep(1000); + + tbCapture.Disconnect(tbChannel.videoChannel); + } + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViENetwork Extended Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViENetwork Extended Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + +int ViEAutoTest::ViENetworkAPITest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViENetwork API Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + tbInterfaces ViE("ViENetworkAPITest", numberOfErrors); // Create VIE + { + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + // + // External transport + // + tbExternalTransport testTransport(*ViE.ptrViENetwork); + error = ViE.ptrViENetwork->RegisterSendTransport(tbChannel.videoChannel, + testTransport); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->RegisterSendTransport(tbChannel.videoChannel, + testTransport); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + unsigned char packet[1500]; + void* ptrPacket = (void*) packet; + packet[0] = 0x80; // V=2, P=0, X=0, CC=0 + packet[1] = 0x78; // M=0, PT = 120 (VP8) + error = ViE.ptrViENetwork->ReceivedRTPPacket(tbChannel.videoChannel, + packet, 1500); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->ReceivedRTCPPacket(tbChannel.videoChannel, + packet, 1500); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->ReceivedRTPPacket(tbChannel.videoChannel, + packet, 1500); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->ReceivedRTCPPacket(tbChannel.videoChannel, + packet, 1500); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->ReceivedRTPPacket(tbChannel.videoChannel, + packet, 11); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->ReceivedRTPPacket(tbChannel.videoChannel, + packet, 11); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->ReceivedRTPPacket(tbChannel.videoChannel, + packet, 3000); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->ReceivedRTPPacket(tbChannel.videoChannel, + packet, 3000); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StopReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->DeregisterSendTransport( + tbChannel.videoChannel); // Sending + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->DeregisterSendTransport( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->DeregisterSendTransport( + tbChannel.videoChannel); // Already deregistered + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // Local receiver + // + // TODO (perkj) change when B 4239431 is fixed. + /*error = ViE.ptrViENetwork->SetLocalReceiver(tbChannel.videoChannel, + 1234, 1234, "127.0.0.1"); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__);*/ + error = ViE.ptrViENetwork->SetLocalReceiver(tbChannel.videoChannel, + 1234, 1235, "127.0.0.1"); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetLocalReceiver(tbChannel.videoChannel, + 1234, 1235, "127.0.0.1"); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetLocalReceiver(tbChannel.videoChannel, + 1236, 1237, "127.0.0.1"); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + unsigned short rtpPort = 0; + unsigned short rtcpPort = 0; + char ipAddress[64]; + memset(ipAddress, 0, 64); + error = ViE.ptrViENetwork->GetLocalReceiver(tbChannel.videoChannel, + rtpPort, rtcpPort, + ipAddress); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetLocalReceiver(tbChannel.videoChannel, + 1234, 1235, "127.0.0.1"); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetLocalReceiver(tbChannel.videoChannel, + rtpPort, rtcpPort, + ipAddress); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StopReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // Send destination + // + error = ViE.ptrViENetwork->SetSendDestination(tbChannel.videoChannel, + "127.0.0.1", 1234, 1235, + 1234, 1235); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendDestination(tbChannel.videoChannel, + "127.0.0.1", 1236, 1237, + 1234, 1235); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + unsigned short sourceRtpPort = 0; + unsigned short sourceRtcpPort = 0; + error = ViE.ptrViENetwork->GetSendDestination(tbChannel.videoChannel, + ipAddress, rtpPort, + rtcpPort, sourceRtpPort, + sourceRtcpPort); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Not allowed while sending + error = ViE.ptrViENetwork->SetSendDestination(tbChannel.videoChannel, + "127.0.0.1", 1234, 1235, + 1234, 1235); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(ViE.ptrViEBase->LastError() + == kViENetworkAlreadySending, "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViENetwork->SetSendDestination(tbChannel.videoChannel, + "127.0.0.1", 1234, 1235, + 1234, 1235); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViENetwork->GetSendDestination(tbChannel.videoChannel, + ipAddress, rtpPort, + rtcpPort, sourceRtpPort, + sourceRtcpPort); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // Address information + // + + // GetSourceInfo: Tested in functional test + error = ViE.ptrViENetwork->GetLocalIP(ipAddress, false); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + // TODO: IPv6 + + // + // Filter + // + error = ViE.ptrViENetwork->GetSourceFilter(tbChannel.videoChannel, + rtpPort, rtcpPort, ipAddress); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSourceFilter(tbChannel.videoChannel, + 1234, 1235, "10.10.10.10"); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSourceFilter(tbChannel.videoChannel, + 1236, 1237, "127.0.0.1"); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSourceFilter(tbChannel.videoChannel, + rtpPort, rtcpPort, ipAddress); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSourceFilter(tbChannel.videoChannel, 0, + 0, NULL); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSourceFilter(tbChannel.videoChannel, + rtpPort, rtcpPort, ipAddress); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + { + tbVideoChannel tbChannel(ViE, numberOfErrors); // Create a video channel + error = ViE.ptrViENetwork->SetLocalReceiver(tbChannel.videoChannel, + 1234); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + int DSCP = 0; + bool useSetSockOpt = false; + // SetSockOpt should work without a locally bind socket + error = ViE.ptrViENetwork->GetSendToS(tbChannel.videoChannel, DSCP, + useSetSockOpt); // No ToS set + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(DSCP == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + // Invalid input + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, -1, true); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + // Invalid input + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, 64, true); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + // Valid + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, 20, true); + + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendToS(tbChannel.videoChannel, DSCP, + useSetSockOpt); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError((DSCP == 20 && useSetSockOpt + == true), "ERROR: %s at line %d", __FUNCTION__, __LINE__); + // Disable + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, 0, true); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendToS(tbChannel.videoChannel, DSCP, + useSetSockOpt); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(DSCP == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + char myIpAddress[64]; + memset(myIpAddress, 0, 64); + // Get local ip to be able to set ToS withtou setSockOpt + error = ViE.ptrViENetwork->GetLocalIP(myIpAddress, false); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetLocalReceiver(tbChannel.videoChannel, + 1234, 1235, myIpAddress); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + // Invalid input + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, -1, + false); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, 64, + false); // Invalid input + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendToS(tbChannel.videoChannel, DSCP, + useSetSockOpt); // No ToS set + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(DSCP == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, 20, + false); // Valid + if (error != 0) + { + ViETest::Log("ViESetSendToS error!."); + ViETest::Log("You must be admin to run these tests."); + ViETest::Log("On Win7 and late Vista, you need to right click the " + "exe and choose"); + ViETest::Log("\"Run as administrator\"\n"); + int dummyChar = getchar(); + } + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendToS(tbChannel.videoChannel, DSCP, + useSetSockOpt); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#ifdef _WIN32 + numberOfErrors += ViETest::TestError((DSCP == 20 + && useSetSockOpt == false), + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#else // useSetSockOpt is true on Linux and Mac + numberOfErrors += ViETest::TestError((DSCP == 20 + && useSetSockOpt == true), + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#endif + error = ViE.ptrViENetwork->SetSendToS(tbChannel.videoChannel, 0, false); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendToS(tbChannel.videoChannel, DSCP, + useSetSockOpt); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(DSCP == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + { + // From qos.h. (*) -> supported by ViE + // + // #define SERVICETYPE_NOTRAFFIC 0x00000000 + // #define SERVICETYPE_BESTEFFORT 0x00000001 (*) + // #define SERVICETYPE_CONTROLLEDLOAD 0x00000002 (*) + // #define SERVICETYPE_GUARANTEED 0x00000003 (*) + // #define SERVICETYPE_NETWORK_UNAVAILABLE 0x00000004 + // #define SERVICETYPE_GENERAL_INFORMATION 0x00000005 + // #define SERVICETYPE_NOCHANGE 0x00000006 + // #define SERVICETYPE_NONCONFORMING 0x00000009 + // #define SERVICETYPE_NETWORK_CONTROL 0x0000000A + // #define SERVICETYPE_QUALITATIVE 0x0000000D (*) + // + // #define SERVICE_BESTEFFORT 0x80010000 + // #define SERVICE_CONTROLLEDLOAD 0x80020000 + // #define SERVICE_GUARANTEED 0x80040000 + // #define SERVICE_QUALITATIVE 0x80200000 + + tbVideoChannel tbChannel(ViE, numberOfErrors); // Create a video channel + + +#if defined(_WIN32) + // No socket + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_BESTEFFORT); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViENetwork->SetLocalReceiver(tbChannel.videoChannel, + 1234); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + // Sender not initialized + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_BESTEFFORT); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendDestination(tbChannel.videoChannel, + "127.0.0.1", 12345); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Try to set all non-supported service types + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_NOTRAFFIC); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_NETWORK_UNAVAILABLE); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_GENERAL_INFORMATION); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_NOCHANGE); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_NONCONFORMING); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_NOTRAFFIC); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_NETWORK_CONTROL); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICE_BESTEFFORT); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICE_CONTROLLEDLOAD); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICE_GUARANTEED); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICE_QUALITATIVE); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Loop through valid service settings + bool enabled = false; + int serviceType = 0; + int overrideDSCP = 0; + + error = ViE.ptrViENetwork->GetSendGQoS(tbChannel.videoChannel, enabled, + serviceType, overrideDSCP); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(enabled == false, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_BESTEFFORT); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendGQoS(tbChannel.videoChannel, enabled, + serviceType, overrideDSCP); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError((enabled == true && serviceType + == SERVICETYPE_BESTEFFORT && overrideDSCP == false), + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_CONTROLLEDLOAD); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendGQoS(tbChannel.videoChannel, enabled, + serviceType, overrideDSCP); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError((enabled == true && serviceType + == SERVICETYPE_CONTROLLEDLOAD && overrideDSCP == false), + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_GUARANTEED); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendGQoS(tbChannel.videoChannel, enabled, + serviceType, overrideDSCP); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError( + (enabled == true + && serviceType == SERVICETYPE_GUARANTEED + && overrideDSCP == false), + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, true, + SERVICETYPE_QUALITATIVE); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendGQoS(tbChannel.videoChannel, enabled, + serviceType, overrideDSCP); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError((enabled == true && serviceType + == SERVICETYPE_QUALITATIVE && overrideDSCP == false), + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetSendGQoS(tbChannel.videoChannel, false, + SERVICETYPE_QUALITATIVE); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->GetSendGQoS(tbChannel.videoChannel, enabled, + serviceType, overrideDSCP); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(enabled == false, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#endif + } + { + // + // MTU and packet burst + // + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors); + // Invalid input + error = ViE.ptrViENetwork->SetMTU(tbChannel.videoChannel, 1600); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + // Invalid input + error = ViE.ptrViENetwork->SetMTU(tbChannel.videoChannel, 800); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // Observer and timeout + // + ViEAutoTestNetworkObserver vieTestObserver; + error = ViE.ptrViENetwork->RegisterObserver(tbChannel.videoChannel, + vieTestObserver); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->RegisterObserver(tbChannel.videoChannel, + vieTestObserver); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetPeriodicDeadOrAliveStatus( + tbChannel.videoChannel, true); // No observer + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->DeregisterObserver(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViENetwork->DeregisterObserver(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViENetwork->SetPeriodicDeadOrAliveStatus( + tbChannel.videoChannel, true); // No observer + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Packet timout notification + error = ViE.ptrViENetwork->SetPacketTimeoutNotification( + tbChannel.videoChannel, true, 10); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } +#if 0 + virtual int SendUDPPacket(const int videoChannel, const void* data, + const unsigned int length, int& transmittedBytes, + bool useRtcpSocket = false) = 0; +#endif + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViENetwork API Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViENetwork API Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_render.cc b/video_engine/main/test/AutoTest/source/vie_autotest_render.cc new file mode 100644 index 0000000000..718775b322 --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_render.cc @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_render.cc +// + +#include "vie_autotest_defines.h" +#include "vie_autotest.h" +#include "engine_configurations.h" + +#include "video_render.h" + +#include "tb_interfaces.h" +#include "tb_video_channel.h" +#include "tb_capture_device.h" + +#if defined(WIN32) +#include +#include +#include +#elif defined(WEBRTC_LINUX) + //From windgi.h + #undef RGB + #define RGB(r,g,b) ((unsigned long)(((unsigned char)(r)|((unsigned short)((unsigned char)(g))<<8))|(((unsigned long)(unsigned char)(b))<<16))) + //From ddraw.h +/* typedef struct _DDCOLORKEY + { + DWORD dwColorSpaceLowValue; // low boundary of color space that is to + DWORD dwColorSpaceHighValue; // high boundary of color space that is + } DDCOLORKEY;*/ +#elif defined(WEBRTC_MAC) +#endif + +class ViEAutoTestExternalRenderer: public ExternalRenderer +{ +public: + ViEAutoTestExternalRenderer() : + _width(0), + _height(0) + { + } + virtual int FrameSizeChange(unsigned int width, unsigned int height, + unsigned int numberOfStreams) + { + _width = width; + _height = height; + return 0; + } + + virtual int DeliverFrame(unsigned char* buffer, int bufferSize) + { + if (bufferSize != _width * _height * 3 / 2) + { + ViETest::Log("incorrect render buffer received, of length = %d\n", + bufferSize); + return 0; + } + ViETest::Log("callback DeliverFrame is good\n"); + return 0; + } + +public: + virtual ~ViEAutoTestExternalRenderer() + { + } +private: + int _width, _height; +}; + +int ViEAutoTest::ViERenderStandardTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViERender Standard Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + int rtpPort = 6000; + + tbInterfaces ViE("ViERender", numberOfErrors); + + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + tbCaptureDevice tbCapture(ViE, numberOfErrors); // Create a capture device + tbCapture.ConnectTo(tbChannel.videoChannel); + tbChannel.StartReceive(rtpPort); + tbChannel.StartSend(rtpPort); + + error = ViE.ptrViERender->RegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->AddRenderer(tbCapture.captureId, _window1, 0, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->StartRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->RegisterVideoRenderModule(*_vrm2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->AddRenderer(tbChannel.videoChannel, _window2, 1, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->StartRender(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("\nCapture device is renderered in Window 1"); + ViETest::Log("Remote stream is renderered in Window 2"); + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViERender->StopRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->RemoveRenderer(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + +#ifndef ANDROID // PIP and full screen rendering is not supported on Android + error = ViE.ptrViERender->DeRegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->AddRenderer(tbCapture.captureId, _window2, 0, + 0.75, 0.75, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->StartRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("\nCapture device is now rendered in Window 2, PiP."); + ViETest::Log("Switching to full screen rendering in %d seconds.\n", + KAutoTestSleepTimeMs / 1000); + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViERender->RemoveRenderer(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->RemoveRenderer(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->DeRegisterVideoRenderModule(*_vrm2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Destroy render module and create new in full screen mode + VideoRender::DestroyVideoRender(_vrm1); + _vrm1 = NULL; + _vrm1 = VideoRender::CreateVideoRender(4563, _window1, true, _renderType); + numberOfErrors += ViETest::TestError(_vrm1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->RegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->AddRenderer(tbCapture.captureId, _window1, 0, + 0.75f, 0.75f, 1.0f, 1.0f); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->AddRenderer(tbChannel.videoChannel, _window1, 1, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViERender->RemoveRenderer(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->RemoveRenderer(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->DeRegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Destroy full screen render module and create new in normal mode + VideoRender::DestroyVideoRender(_vrm1); + _vrm1 = NULL; + _vrm1 = VideoRender::CreateVideoRender(4561, _window1, false, _renderType); + numberOfErrors += ViETest::TestError(_vrm1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); +#endif + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + tbCapture.Disconnect(tbChannel.videoChannel); + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViERender Standard Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViERender Standard Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + + return 0; +} + +int ViEAutoTest::ViERenderExtendedTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViERender Extended Test\n"); + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + int rtpPort = 6000; + + tbInterfaces ViE("ViERender_API", numberOfErrors); + + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + tbCaptureDevice tbCapture(ViE, numberOfErrors); // Create a capture device + tbCapture.ConnectTo(tbChannel.videoChannel); + tbChannel.StartReceive(rtpPort); + tbChannel.StartSend(rtpPort); + + error = ViE.ptrViERender->RegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->AddRenderer(tbCapture.captureId, _window1, 0, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->StartRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->RegisterVideoRenderModule(*_vrm2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->AddRenderer(tbChannel.videoChannel, _window2, 1, + 0.0, 0.0, 1.0, 1.0); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->StartRender(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("\nCapture device is renderered in Window 1"); + ViETest::Log("Remote stream is renderered in Window 2"); + AutoTestSleep(KAutoTestSleepTimeMs); + +#ifdef _WIN32 + ViETest::Log("\nConfiguring Window2"); + ViETest::Log("you will see video only in first quadrant"); + error = ViE.ptrViERender->ConfigureRender(tbChannel.videoChannel, 0, 0.0f, + 0.0f, 0.5f, 0.5f); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + AutoTestSleep(KAutoTestSleepTimeMs); + + ViETest::Log("you will see video only in fourth quadrant"); + error = ViE.ptrViERender->ConfigureRender(tbChannel.videoChannel, 0, 0.5f, + 0.5f, 1.0f, 1.0f); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + AutoTestSleep(KAutoTestSleepTimeMs); + + ViETest::Log("normal video on Window2"); + error = ViE.ptrViERender->ConfigureRender(tbChannel.videoChannel, 0, 0.0f, + 0.0f, 1.0f, 1.0f); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + AutoTestSleep(KAutoTestSleepTimeMs); +#endif + + ViETest::Log("Mirroring Local Preview (Window1) Left-Right"); + error = ViE.ptrViERender->MirrorRenderStream(tbCapture.captureId, true, + false, true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + AutoTestSleep(KAutoTestSleepTimeMs); + + ViETest::Log("\nMirroring Local Preview (Window1) Left-Right and Up-Down"); + error = ViE.ptrViERender->MirrorRenderStream(tbCapture.captureId, true, + true, true); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + AutoTestSleep(KAutoTestSleepTimeMs); + + ViETest::Log("\nMirroring Remote Window(Window2) Up-Down"); + error = ViE.ptrViERender->MirrorRenderStream(tbChannel.videoChannel, true, + true, false); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + AutoTestSleep(KAutoTestSleepTimeMs); + + ViETest::Log("Disabling Mirroing on Window1 and Window2"); + error = ViE.ptrViERender->MirrorRenderStream(tbCapture.captureId, false, + false, false); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + AutoTestSleep(KAutoTestSleepTimeMs); + error = ViE.ptrViERender->MirrorRenderStream(tbChannel.videoChannel, false, + false, false); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + AutoTestSleep(KAutoTestSleepTimeMs); + + ViETest::Log("\nEnabling Full Screen render in 5 sec"); + + error = ViE.ptrViERender->RemoveRenderer(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->DeRegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->RemoveRenderer(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->DeRegisterVideoRenderModule(*_vrm2); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Destroy render module and create new in full screen mode + VideoRender::DestroyVideoRender(_vrm1); + _vrm1 = NULL; + _vrm1 = VideoRender::CreateVideoRender(4563, _window1, true, _renderType); + numberOfErrors += ViETest::TestError(_vrm1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->RegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->AddRenderer(tbCapture.captureId, _window1, 0, + 0.0f, 0.0f, 1.0f, 1.0f); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViERender->StopRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + /* error = ViE.ptrViERender->StopRender(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + */ + ViETest::Log("\nStop renderer"); + + error = ViE.ptrViERender->RemoveRenderer(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + /* error = ViE.ptrViERender->RemoveRenderer(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__); + */ + ViETest::Log("\nRemove renderer"); + + error = ViE.ptrViERender->DeRegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Destroy full screen render module and create new for external rendering + VideoRender::DestroyVideoRender(_vrm1); + _vrm1 = NULL; + _vrm1 = VideoRender::CreateVideoRender(4564, NULL, false, _renderType); + numberOfErrors += ViETest::TestError(_vrm1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->RegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("\nExternal Render Test"); + ViEAutoTestExternalRenderer externalRenderObj; + error = ViE.ptrViERender->AddRenderer(tbCapture.captureId, + webrtc::kVideoI420, + &externalRenderObj); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->StartRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViERender->StopRender(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERender->RemoveRenderer(tbCapture.captureId); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERender->DeRegisterVideoRenderModule(*_vrm1); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Destroy render module for external rendering and create new in normal + // mode + VideoRender::DestroyVideoRender(_vrm1); + _vrm1 = NULL; + _vrm1 = VideoRender::CreateVideoRender(4561, _window1, false, _renderType); + numberOfErrors += ViETest::TestError(_vrm1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + tbCapture.Disconnect(tbChannel.videoChannel); + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViERender Extended Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViERender Extended Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + + return 0; +} + +int ViEAutoTest::ViERenderAPITest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViERender API Test\n"); + + int error = 0; + int numberOfErrors = 0; + + //TODO add the real tests cases + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViERender API Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViERender API Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + + return 0; +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_rtp_rtcp.cc b/video_engine/main/test/AutoTest/source/vie_autotest_rtp_rtcp.cc new file mode 100644 index 0000000000..d76ff51c7c --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_rtp_rtcp.cc @@ -0,0 +1,966 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_rtp_rtcp.cc +// +#include + +#include "vie_autotest_defines.h" +#include "vie_autotest.h" +#include "engine_configurations.h" + +#include "tb_capture_device.h" +#include "tb_external_transport.h" +#include "tb_interfaces.h" +#include "tb_video_channel.h" + +class ViERtpObserver: public ViERTPObserver +{ +public: + ViERtpObserver() + { + } + virtual ~ViERtpObserver() + { + } + + virtual void IncomingSSRCChanged(const int videoChannel, + const unsigned int SSRC) + { + } + virtual void IncomingCSRCChanged(const int videoChannel, + const unsigned int CSRC, const bool added) + { + } +}; + +class ViERtcpObserver: public ViERTCPObserver +{ +public: + int _channel; + unsigned char _subType; + unsigned int _name; + char* _data; + unsigned short _dataLength; + + ViERtcpObserver() : + _channel(-1), + _subType(0), + _name(-1), + _data(NULL), + _dataLength(0) + { + } + ~ViERtcpObserver() + { + if (_data) + { + delete[] _data; + } + } + virtual void OnApplicationDataReceived( + const int videoChannel, const unsigned char subType, + const unsigned int name, const char* data, + const unsigned short dataLengthInBytes) + { + _channel = videoChannel; + _subType = subType; + _name = name; + if (dataLengthInBytes > _dataLength) + { + delete[] _data; + _data = NULL; + } + if (_data == NULL) + { + _data = new char[dataLengthInBytes]; + } + memcpy(_data, data, dataLengthInBytes); + _dataLength = dataLengthInBytes; + } +}; + +int ViEAutoTest::ViERtpRtcpStandardTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViERTP_RTCP Standard Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + int rtpPort = 6000; + // Create VIE + tbInterfaces ViE("ViERtpRtcpStandardTest", numberOfErrors); + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + + // Create a capture device + tbCaptureDevice tbCapture(ViE, numberOfErrors); + tbCapture.ConnectTo(tbChannel.videoChannel); + + ViETest::Log("\n"); + tbExternalTransport myTransport(*(ViE.ptrViENetwork)); + + error = ViE.ptrViENetwork->RegisterSendTransport(tbChannel.videoChannel, + myTransport); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + + + + unsigned short startSequenceNumber = 12345; + ViETest::Log("Set start sequence number: %u\n"); + error = ViE.ptrViERtpRtcp->SetStartSequenceNumber(tbChannel.videoChannel, + startSequenceNumber); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + myTransport.EnableSequenceNumberCheck(); + + error = ViE.ptrViEBase->StartReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + AutoTestSleep(1000); + + unsigned short receivedSequenceNumber = + myTransport.GetFirstSequenceNumber(); + ViETest::Log("First received sequence number: %u\n\n"); + numberOfErrors += ViETest::TestError( + receivedSequenceNumber == startSequenceNumber, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // RTCP CName + // + ViETest::Log("Testing CName\n\n"); + char* sendCName = "ViEAutoTestCName\0"; + error = ViE.ptrViERtpRtcp->SetRTCPCName(tbChannel.videoChannel, sendCName); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + char returnCName[ViERTP_RTCP::KMaxRTCPCNameLength]; + memset(returnCName, 0, ViERTP_RTCP::KMaxRTCPCNameLength); + error + = ViE.ptrViERtpRtcp->GetRTCPCName(tbChannel.videoChannel, returnCName); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError((strcmp(sendCName, returnCName) == 0), + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + AutoTestSleep(1000); + + char remoteCName[ViERTP_RTCP::KMaxRTCPCNameLength]; + memset(remoteCName, 0, ViERTP_RTCP::KMaxRTCPCNameLength); + error = ViE.ptrViERtpRtcp->GetRemoteRTCPCName(tbChannel.videoChannel, + remoteCName); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError((strcmp(sendCName, remoteCName) == 0), + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // + // Statistics + // + // Stop and restart to clear stats + ViETest::Log("Testing statistics\n\n"); + error = ViE.ptrViEBase->StopReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + myTransport.ClearStats(); + std::cout << "Enter Packet Loss Percentage" << std::endl; + std::string rate_str; + std::getline(std::cin, rate_str); + int rate = atoi(rate_str.c_str()); + myTransport.SetPacketLoss(rate); + + // Start send to verify sending stats + + error = ViE.ptrViERtpRtcp->SetStartSequenceNumber(tbChannel.videoChannel, + startSequenceNumber); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + AutoTestSleep(KAutoTestSleepTimeMs); + + unsigned short sentFractionsLost = 0; + unsigned int sentCumulativeLost = 0; + unsigned int sentExtendedMax = 0; + unsigned int sentJitter = 0; + int sentRttMs = 0; + unsigned short recFractionsLost = 0; + unsigned int recCumulativeLost = 0; + unsigned int recExtendedMax = 0; + unsigned int recJitter = 0; + int recRttMs = 0; + + error = ViE.ptrViEBase->StopReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + AutoTestSleep(2000); + + error = ViE.ptrViERtpRtcp->GetSentRTCPStatistics(tbChannel.videoChannel, + sentFractionsLost, + sentCumulativeLost, + sentExtendedMax, + sentJitter, sentRttMs); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError((sentCumulativeLost > 0 + && sentExtendedMax > startSequenceNumber && sentJitter > 0 && sentRttMs + > 0), "ERROR: %s at line %d", __FUNCTION__, __LINE__); + + error = ViE.ptrViERtpRtcp->GetReceivedRTCPStatistics(tbChannel.videoChannel, + recFractionsLost, + recCumulativeLost, + recExtendedMax, + recJitter, recRttMs); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError( + (recCumulativeLost > 0 + && recExtendedMax > startSequenceNumber + && recJitter > 0 + && recRttMs > 0), + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + // Check that rec stats extended max is greater than what we've sent. + numberOfErrors += ViETest::TestError(recExtendedMax >= sentExtendedMax, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // + // Keepalive + // + ViETest::Log("Testing RTP keep alive...\n\n"); + error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StartReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + myTransport.SetPacketLoss(0); + myTransport.ClearStats(); + + const char keepAlivePT = 109; + unsigned int deltaTimeSeconds = 2; + error = ViE.ptrViERtpRtcp->SetRTPKeepAliveStatus(tbChannel.videoChannel, + true, keepAlivePT, + deltaTimeSeconds); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViERtpRtcp->SetRTPKeepAliveStatus(tbChannel.videoChannel, + false, keepAlivePT, + deltaTimeSeconds); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + WebRtc_Word32 numRtpPackets = 0; + WebRtc_Word32 numDroppedPackets = 0; + WebRtc_Word32 numRtcpPackets = 0; + myTransport.GetStats(numRtpPackets, numDroppedPackets, numRtcpPackets); + numberOfErrors += ViETest::TestError(numRtpPackets == KAutoTestSleepTimeMs + / (1000 * deltaTimeSeconds), "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // Test to set SSRC + unsigned int setSSRC = 0x01234567; + ViETest::Log("Set SSRC %u\n"); + error = ViE.ptrViERtpRtcp->SetLocalSSRC(tbChannel.videoChannel, setSSRC); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + myTransport.EnableSSRCCheck(); + + AutoTestSleep(2000); + unsigned int receivedSSRC = myTransport.ReceivedSSRC(); + ViETest::Log("Received SSRC %u\n\n"); + numberOfErrors += ViETest::TestError(setSSRC == receivedSSRC, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + unsigned int localSSRC = 0; + error = ViE.ptrViERtpRtcp->GetLocalSSRC(tbChannel.videoChannel, localSSRC); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(localSSRC == setSSRC, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + unsigned int remoteSSRC = 0; + error + = ViE.ptrViERtpRtcp->GetRemoteSSRC(tbChannel.videoChannel, remoteSSRC); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(remoteSSRC == setSSRC, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + + ViETest::Log("Testing RTP dump...\n\n"); + +#ifdef ANDROID + char* inDumpName = "/sdcard/IncomingRTPDump.rtp"; + char* outDumpName = "/sdcard/OutgoingRTPDump.rtp"; +#else + char* inDumpName = "IncomingRTPDump.rtp"; + char* outDumpName = "OutgoingRTPDump.rtp"; +#endif + + error = ViE.ptrViERtpRtcp->StartRTPDump(tbChannel.videoChannel, inDumpName, + kRtpIncoming); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->StartRTPDump(tbChannel.videoChannel, + outDumpName, kRtpOutgoing); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + AutoTestSleep(KAutoTestSleepTimeMs); + + error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + AutoTestSleep(1000); + + error + = ViE.ptrViERtpRtcp->StopRTPDump(tbChannel.videoChannel, kRtpIncoming); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error + = ViE.ptrViERtpRtcp->StopRTPDump(tbChannel.videoChannel, kRtpOutgoing); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // Make sure data was actuall saved to the file and we stored the same + // amount of data in both files + FILE* inDump = fopen(inDumpName, "r"); + fseek(inDump, 0L, SEEK_END); + long inEndPos = ftell(inDump); + fclose(inDump); + FILE* outDump = fopen(outDumpName, "r"); + fseek(outDump, 0L, SEEK_END); + long outEndPos = ftell(outDump); + fclose(outDump); + + numberOfErrors += ViETest::TestError((inEndPos > 0 + && inEndPos < outEndPos + 100), + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // Deregister external transport + error = ViE.ptrViENetwork->DeregisterSendTransport(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViERTP_RTCP Standard Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViERTP_RTCP Standard Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + +int ViEAutoTest::ViERtpRtcpExtendedTest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViERTP_RTCP Extended Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + numberOfErrors = ViERtpRtcpStandardTest(); + + int rtpPort = 6000; + // Create VIE + tbInterfaces ViE("ViERtpRtcpStandardTest", numberOfErrors); + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + // Create a capture device + tbCaptureDevice tbCapture(ViE, numberOfErrors); + tbCapture.ConnectTo(tbChannel.videoChannel); + + //tbChannel.StartReceive(rtpPort); + //tbChannel.StartSend(rtpPort); + tbExternalTransport myTransport(*(ViE.ptrViENetwork)); + + error = ViE.ptrViENetwork->RegisterSendTransport(tbChannel.videoChannel, + myTransport); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + + // + // Application specific RTCP + // + // + + ViERtcpObserver rtcpObserver; + error = ViE.ptrViERtpRtcp->RegisterRTCPObserver(tbChannel.videoChannel, + rtcpObserver); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + unsigned char subType = 3; + unsigned int name = static_cast (0x41424344); // 'ABCD'; + const char* data = "ViEAutoTest Data of length 32 --"; + const unsigned short numBytes = 32; + + error = ViE.ptrViERtpRtcp->SendApplicationDefinedRTCPPacket( + tbChannel.videoChannel, subType, name, data, numBytes); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViETest::Log("Sending RTCP application data...\n"); + AutoTestSleep(KAutoTestSleepTimeMs); + numberOfErrors += ViETest::TestError( + (subType = rtcpObserver._subType + && !strncmp(data, rtcpObserver._data, 32) + && name == rtcpObserver._name + && numBytes == rtcpObserver._dataLength), + "ERROR: %s at line %d", __FUNCTION__, __LINE__); + ViETest::Log("\t RTCP application data received\n"); + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + + error = ViE.ptrViEBase->StopReceive(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViENetwork->DeregisterSendTransport(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViERTP_RTCP Extended Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViERTP_RTCP Extended Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} + +int ViEAutoTest::ViERtpRtcpAPITest() +{ + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViERTP_RTCP API Test\n"); + + //*************************************************************** + // Begin create/initialize WebRTC Video Engine for testing + //*************************************************************** + + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + + int rtpPort = 6000; + // Create VIE + tbInterfaces ViE("ViERtpRtcpAPITest", numberOfErrors); + // Create a video channel + tbVideoChannel tbChannel(ViE, numberOfErrors, webrtc::kVideoCodecVP8); + // Create a capture device + tbCaptureDevice tbCapture(ViE, numberOfErrors); + tbCapture.ConnectTo(tbChannel.videoChannel); + + //*************************************************************** + // Engine ready. Begin testing class + //*************************************************************** + + + // + // Check different RTCP modes + // + ViERTCPMode rtcpMode = kRtcpNone; + error = ViE.ptrViERtpRtcp->GetRTCPStatus(tbChannel.videoChannel, rtcpMode); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(rtcpMode == kRtcpCompound_RFC4585, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + error = ViE.ptrViERtpRtcp->SetRTCPStatus(tbChannel.videoChannel, + kRtcpCompound_RFC4585); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->GetRTCPStatus(tbChannel.videoChannel, rtcpMode); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(rtcpMode == kRtcpCompound_RFC4585, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + error = ViE.ptrViERtpRtcp->SetRTCPStatus(tbChannel.videoChannel, + kRtcpNonCompound_RFC5506); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->GetRTCPStatus(tbChannel.videoChannel, rtcpMode); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(rtcpMode == kRtcpNonCompound_RFC5506, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + error = ViE.ptrViERtpRtcp->SetRTCPStatus(tbChannel.videoChannel, kRtcpNone); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->GetRTCPStatus(tbChannel.videoChannel, rtcpMode); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError(rtcpMode == kRtcpNone, + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + error = ViE.ptrViERtpRtcp->SetRTCPStatus(tbChannel.videoChannel, + kRtcpCompound_RFC4585); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + // + // CName is testedn in SimpleTest + // Start sequence number is tested in SimplTEst + // + char* testCName = "ViEAutotestCName"; + error = ViE.ptrViERtpRtcp->SetRTCPCName(tbChannel.videoChannel, testCName); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + char returnCName[256]; + memset(returnCName, 0, 256); + error + = ViE.ptrViERtpRtcp->GetRTCPCName(tbChannel.videoChannel, returnCName); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError((strcmp(testCName, returnCName) == 0), + "ERROR: %s at line %d", __FUNCTION__, + __LINE__); + + // + // SSRC + // + error = ViE.ptrViERtpRtcp->SetLocalSSRC(tbChannel.videoChannel, 0x01234567); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SetLocalSSRC(tbChannel.videoChannel, 0x76543210); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + unsigned int ssrc = 0; + error = ViE.ptrViERtpRtcp->GetLocalSSRC(tbChannel.videoChannel, ssrc); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERtpRtcp->SetStartSequenceNumber(tbChannel.videoChannel, + 1000); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + tbChannel.StartSend(); + error = ViE.ptrViERtpRtcp->SetStartSequenceNumber(tbChannel.videoChannel, + 12345); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + tbChannel.StopSend(); + + // + // Start sequence number + // + error = ViE.ptrViERtpRtcp->SetStartSequenceNumber(tbChannel.videoChannel, + 12345); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SetStartSequenceNumber(tbChannel.videoChannel, + 1000); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + tbChannel.StartSend(); + error = ViE.ptrViERtpRtcp->SetStartSequenceNumber(tbChannel.videoChannel, + 12345); + numberOfErrors += ViETest::TestError(error == -1, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + tbChannel.StopSend(); + + // + // Application specific RTCP + // + { + unsigned char subType = 3; + unsigned int name = static_cast (0x41424344); // 'ABCD'; + const char* data = "ViEAutoTest Data of length 32 --"; + const unsigned short numBytes = 32; + + tbChannel.StartSend(); + error = ViE.ptrViERtpRtcp->SendApplicationDefinedRTCPPacket( + tbChannel.videoChannel, subType, name, data, numBytes); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SendApplicationDefinedRTCPPacket( + tbChannel.videoChannel, subType, name, NULL, numBytes); + // NULL input + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SendApplicationDefinedRTCPPacket( + tbChannel.videoChannel, subType, name, data, numBytes - 1); + // incorrect length + numberOfErrors += ViETest::TestError(error != 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->GetRTCPStatus(tbChannel.videoChannel, + rtcpMode); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SendApplicationDefinedRTCPPacket( + tbChannel.videoChannel, subType, name, data, numBytes); + // RTCP off + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SetRTCPStatus(tbChannel.videoChannel, + kRtcpCompound_RFC4585); + numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + tbChannel.StopSend(); + error = ViE.ptrViERtpRtcp->SendApplicationDefinedRTCPPacket( + tbChannel.videoChannel, subType, name, data, numBytes); + // Not sending + numberOfErrors += ViETest::TestError(error != 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + + // + // Statistics + // + // Tested in SimpleTest(), we'll get errors if we haven't received a RTCP + // packet. + + // + // RTP Keepalive + // + { + char setPT = 123; + unsigned int setDeltaTime = 10; + bool enabled = false; + char getPT = 0; + unsigned int getDeltaTime = 0; + error = ViE.ptrViERtpRtcp->SetRTPKeepAliveStatus(tbChannel.videoChannel, + true, 119); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SetRTPKeepAliveStatus(tbChannel.videoChannel, + true, setPT, + setDeltaTime); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SetRTPKeepAliveStatus(tbChannel.videoChannel, + false, setPT, + setDeltaTime); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SetRTPKeepAliveStatus(tbChannel.videoChannel, + true, setPT, + setDeltaTime); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERtpRtcp->GetRTPKeepAliveStatus(tbChannel.videoChannel, + enabled, getPT, + getDeltaTime); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + numberOfErrors += ViETest::TestError((enabled == true, + setPT == getPT, + setDeltaTime == getDeltaTime), + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + error = ViE.ptrViERtpRtcp->SetRTPKeepAliveStatus(tbChannel.videoChannel, + true, setPT, + setDeltaTime); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + tbChannel.StopSend(); + error = ViE.ptrViERtpRtcp->SetRTPKeepAliveStatus(tbChannel.videoChannel, + enabled, getPT, 0); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SetRTPKeepAliveStatus(tbChannel.videoChannel, + enabled, getPT, 61); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + // + // RTP Dump + // + { +#ifdef ANDROID + char* dumpName = "/sdcard/DumpFileName.rtp"; +#else + char* dumpName = "DumpFileName.rtp"; +#endif + error = ViE.ptrViERtpRtcp->StartRTPDump(tbChannel.videoChannel, + dumpName, kRtpIncoming); + + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->StopRTPDump(tbChannel.videoChannel, + kRtpIncoming); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->StopRTPDump(tbChannel.videoChannel, + kRtpIncoming); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->StartRTPDump(tbChannel.videoChannel, + dumpName, kRtpOutgoing); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->StopRTPDump(tbChannel.videoChannel, + kRtpOutgoing); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->StopRTPDump(tbChannel.videoChannel, + kRtpOutgoing); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->StartRTPDump(tbChannel.videoChannel, + dumpName, (RTPDirections) 3); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + // + // RTP/RTCP Observers + // + { + ViERtpObserver rtpObserver; + error = ViE.ptrViERtpRtcp->RegisterRTPObserver(tbChannel.videoChannel, + rtpObserver); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->RegisterRTPObserver(tbChannel.videoChannel, + rtpObserver); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->DeregisterRTPObserver( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->DeregisterRTPObserver( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + + ViERtcpObserver rtcpObserver; + error = ViE.ptrViERtpRtcp->RegisterRTCPObserver(tbChannel.videoChannel, + rtcpObserver); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->RegisterRTCPObserver(tbChannel.videoChannel, + rtcpObserver); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->DeregisterRTCPObserver( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->DeregisterRTCPObserver( + tbChannel.videoChannel); + numberOfErrors += ViETest::TestError(error == -1, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + // + // PLI + // + { + error = ViE.ptrViERtpRtcp->SetKeyFrameRequestMethod( + tbChannel.videoChannel, kViEKeyFrameRequestPliRtcp); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SetKeyFrameRequestMethod( + tbChannel.videoChannel, kViEKeyFrameRequestPliRtcp); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SetKeyFrameRequestMethod( + tbChannel.videoChannel, kViEKeyFrameRequestNone); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + error = ViE.ptrViERtpRtcp->SetKeyFrameRequestMethod( + tbChannel.videoChannel, kViEKeyFrameRequestNone); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + // + // NACK + // + { + error = ViE.ptrViERtpRtcp->SetNACKStatus(tbChannel.videoChannel, true); + numberOfErrors += ViETest::TestError(error == 0, + "ERROR: %s at line %d", + __FUNCTION__, __LINE__); + } + + //*************************************************************** + // Testing finished. Tear down Video Engine + //*************************************************************** + + if (numberOfErrors > 0) + { + // Test failed + ViETest::Log(" "); + ViETest::Log(" ERROR ViERTP_RTCP API Test FAILED!"); + ViETest::Log(" Number of errors: %d", numberOfErrors); + ViETest::Log("========================================"); + ViETest::Log(" "); + return numberOfErrors; + } + + ViETest::Log(" "); + ViETest::Log(" ViERTP_RTCP API Test PASSED!"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 0; +} diff --git a/video_engine/main/test/AutoTest/source/vie_autotest_windows.cc b/video_engine/main/test/AutoTest/source/vie_autotest_windows.cc new file mode 100644 index 0000000000..1d264d11ff --- /dev/null +++ b/video_engine/main/test/AutoTest/source/vie_autotest_windows.cc @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// vie_autotest_windows.cc +// + +#include "vie_autotest_windows.h" + +#include "vie_autotest_defines.h" +#include "vie_autotest_main.h" + +#include "engine_configurations.h" +#include "critical_section_wrapper.h" +#include "thread_wrapper.h" + +#include + +#ifdef _DEBUG +//#include "vld.h" +#endif + +// Disable Visual studio warnings +// 'this' : used in base member initializer list +#pragma warning(disable: 4355) +// new behavior: elements of array 'XXX' will be default initialized +#pragma warning(disable: 4351) + +LRESULT CALLBACK ViEAutoTestWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_DESTROY: + PostQuitMessage( WM_QUIT); + break; + case WM_COMMAND: + break; + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +ViEAutoTestWindowManager::ViEAutoTestWindowManager() : + _window1(NULL), + _window2(NULL), + _terminate(false), + _eventThread(*webrtc::ThreadWrapper::CreateThread(EventProcess, this, + webrtc::kNormalPriority, + "ViEAutotestEventThread")), + _crit(*webrtc::CriticalSectionWrapper::CreateCriticalSection()), + _hwnd1(NULL), + _hwnd2(NULL), + _hwnd1Size(), + _hwnd2Size(), + _hwnd1Title(), + _hwnd2Title() +{ +} + +ViEAutoTestWindowManager::~ViEAutoTestWindowManager() +{ + if (_hwnd1) + { + ViEDestroyWindow(_hwnd1); + } + if (_hwnd2) + { + ViEDestroyWindow(_hwnd1); + } + delete &_crit; +} + +void* ViEAutoTestWindowManager::GetWindow1() +{ + return _window1; +} + +void* ViEAutoTestWindowManager::GetWindow2() +{ + return _window2; +} + +int ViEAutoTestWindowManager::CreateWindows(AutoTestRect window1Size, + AutoTestRect window2Size, + void* window1Title, + void* window2Title) +{ + _hwnd1Size.Copy(window1Size); + _hwnd2Size.Copy(window2Size); + memcpy(_hwnd1Title, window1Title, TITLE_LENGTH); + memcpy(_hwnd2Title, window2Title, TITLE_LENGTH); + + unsigned int tId = 0; + _eventThread.Start(tId); + + do + { + _crit.Enter(); + if (_window1 != NULL) + break; + _crit.Leave(); + AutoTestSleep(10); + } while (true); + _crit.Leave(); + return 0; +} + +int ViEAutoTestWindowManager::TerminateWindows() +{ + _eventThread.SetNotAlive(); + + _terminate = true; + if (_eventThread.Stop()) + { + _crit.Enter(); + delete &_eventThread; + _crit.Leave(); + } + + return 0; +} + +bool ViEAutoTestWindowManager::EventProcess(void* obj) +{ + return static_cast (obj)->EventLoop(); +} + +bool ViEAutoTestWindowManager::EventLoop() +{ + _crit.Enter(); + + //ViECreateWindow(_hwnd1, 352, 288, 600, 100, "ViE Autotest Window 1"); + //ViECreateWindow(_hwnd2, 352, 288, 1000, 100, "ViE Autotest Window 2"); + + ViECreateWindow(_hwnd1, _hwnd1Size.origin.x, _hwnd1Size.origin.y, + _hwnd1Size.size.width, _hwnd1Size.size.height, _hwnd1Title); + ViECreateWindow(_hwnd2, _hwnd2Size.origin.x, _hwnd2Size.origin.y, + _hwnd2Size.size.width, _hwnd2Size.size.height, _hwnd2Title); + + _window1 = (void*) _hwnd1; + _window2 = (void*) _hwnd2; + MSG msg; + while (!_terminate) + { + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + _crit.Leave(); + AutoTestSleep(10); + _crit.Enter(); + } + ViEDestroyWindow(_hwnd1); + ViEDestroyWindow(_hwnd2); + _crit.Leave(); + + return false; +} + +int ViEAutoTestWindowManager::ViECreateWindow(HWND &hwndMain, int xPos, + int yPos, int width, int height, + TCHAR* className) +{ + HINSTANCE hinst = GetModuleHandle(0); + WNDCLASSEX wcx; + wcx.hInstance = hinst; + wcx.lpszClassName = className; + wcx.lpfnWndProc = (WNDPROC) ViEAutoTestWinProc; + wcx.style = CS_DBLCLKS; + wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wcx.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + wcx.hCursor = LoadCursor(NULL, IDC_ARROW); + wcx.lpszMenuName = NULL; + wcx.cbSize = sizeof(WNDCLASSEX); + wcx.cbClsExtra = 0; + wcx.cbWndExtra = 0; + wcx.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + + // Register our window class with the operating system. + // If there is an error, exit program. + ViETest::TestError(RegisterClassEx(&wcx) != NULL, + "Could not register autotest window"); + + // Create the main window. + hwndMain = CreateWindowEx(0, // no extended styles + className, // class name + className, // window name + WS_OVERLAPPED | WS_THICKFRAME,// overlapped window + xPos, // horizontal position + yPos, // vertical position + width, // width + height, // height + (HWND) NULL, // no parent or owner window + (HMENU) NULL, // class menu used + hinst, // instance handle + NULL); // no window creation data + + if (!hwndMain) + { + int error = GetLastError(); + return -1; + } + + // Show the window using the flag specified by the program + // that started the application, and send the application + // a WM_PAINT message. + + ShowWindow(hwndMain, SW_SHOWDEFAULT); + UpdateWindow(hwndMain); + + ::SetWindowPos(hwndMain, HWND_TOP, xPos, yPos, width, height, + SWP_FRAMECHANGED); + + return 0; +} + +int ViEAutoTestWindowManager::ViEDestroyWindow(HWND& hwnd) +{ + ::DestroyWindow(hwnd); + return 0; +} + +bool ViEAutoTestWindowManager::SetTopmostWindow() +{ + + // meant to put terminal window on top + + return true; +} + +int main(int argc, char* argv[]) +{ + + ViEAutoTestMain autoTest; + if (argc > 1) + { + autoTest.UseAnswerFile(argv[1]); + } + return autoTest.BeginOSIndependentTesting(); + +} diff --git a/video_engine/main/test/AutoTest/vie_auto_test.gypi b/video_engine/main/test/AutoTest/vie_auto_test.gypi new file mode 100644 index 0000000000..c3a1749595 --- /dev/null +++ b/video_engine/main/test/AutoTest/vie_auto_test.gypi @@ -0,0 +1,183 @@ +# Copyright (c) 2009 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. + +{ + 'includes': [ + '../../../../common_settings.gypi', # Common settings + ], + 'targets': [ + { + 'target_name': 'vie_auto_test', + 'type': 'executable', + 'dependencies': [ + 'system_wrappers/source/system_wrappers.gyp:system_wrappers', + 'modules/video_render/main/source/video_render.gyp:video_render_module', + 'modules/video_capture/main/source/video_capture.gyp:video_capture_module', + 'voice_engine/main/source/voice_engine_core.gyp:voice_engine_core', + 'video_engine/main/source/video_engine_core.gyp:video_engine_core', + ], + 'include_dirs': [ + 'interface/', + '../../interface', + '../../source', + '../../../../modules/video_coding/codecs/interface/', + ], + 'sources': [ + # interfaces + 'interface/tb_capture_device.h', + 'interface/tb_external_transport.h', + 'interface/tb_I420_codec.h', + 'interface/tb_interfaces.h', + 'interface/tb_video_channel.h', + 'interface/vie_autotest.h', + 'interface/vie_autotest_defines.h', + 'interface/vie_autotest_linux.h', + 'interface/vie_autotest_mac_carbon.h', + 'interface/vie_autotest_mac_cocoa.h', + 'interface/vie_autotest_main.h', + 'interface/vie_autotest_window_manager_interface.h', + 'interface/vie_autotest_windows.h', + + # PLATFORM INDEPENDENT SOURCE FILES + 'source/tb_capture_device.cc', + 'source/tb_external_transport.cc', + 'source/tb_I420_codec.cc', + 'source/tb_interfaces.cc', + 'source/tb_video_channel.cc', + 'source/vie_autotest.cc', + 'source/vie_autotest_base.cc', + 'source/vie_autotest_capture.cc', + 'source/vie_autotest_codec.cc', + 'source/vie_autotest_encryption.cc', + 'source/vie_autotest_file.cc', + 'source/vie_autotest_image_process.cc', + 'source/vie_autotest_loopback.cc', + 'source/vie_autotest_main.cc', + 'source/vie_autotest_network.cc', + 'source/vie_autotest_render.cc', + 'source/vie_autotest_rtp_rtcp.cc', + 'source/vie_autotest_custom_call.cc', + # PLATFORM SPECIFIC SOURCE FILES - Will be filtered below + # Linux + 'source/vie_autotest_linux.cc', + # Mac + 'source/vie_autotest_mac_cocoa.cc', + 'source/vie_autotest_mac_carbon.cc', + # Windows + 'source/vie_autotest_windows.cc', + ], # sources + 'conditions': [ + # DEFINE PLATFORM SPECIFIC SOURCE FILES + ['OS!="linux"', { + 'sources!': [ + 'source/vie_autotest_linux.cc', + ], + }], + ['OS!="mac"', { + 'sources!': [ + 'source/vie_autotest_mac_cocoa.cc', + 'source/vie_autotest_mac_carbon.cc', + ], + }], + ['OS!="win"', { + 'sources!': [ + 'source/vie_autotest_windows.cc', + ], + }], + ['OS=="win"', { + 'dependencies': [ + 'video_engine/main/test/WindowsTest/windowstest.gyp:vie_win_test', + ], + }], + + # DEFINE PLATFORM SPECIFIC INCLUDE AND CFLAGS + ['OS=="mac" or OS=="linux"', { + 'cflags': [ + '-Wno-write-strings', + ], + 'ldflags': [ + '-lpthread -lm', + ], + }], + ['OS=="linux"', { + 'ldflags': [ + # '-L<(libvpx_hack_dir)/<(OS)/<(target_arch)', + ], + 'libraries': [ + '-lrt', + '-lXext', + '-lX11', + '-lasound', + '-lpulse', + + + ], + }], + ['OS=="mac"', { + 'xcode_settings': { + 'OTHER_CPLUSPLUSFLAGS': '-x objective-c++', + 'OTHER_LDFLAGS': [ + '-framework Foundation -framework AppKit -framework Cocoa -framework OpenGL -framework CoreVideo -framework CoreAudio -framework AudioToolbox', + ], + }, + }], + #Copy media files + ['OS=="linux" or OS=="mac"', { + 'actions': [ + { + 'action_name': 'copy media files', + 'inputs': [ + 'media', + ], + 'outputs': [ + 'media_files_in_tmp', + ], + 'action': [ + '/bin/sh', '-c', + 'mkdir -p /tmp/vie_auto_test; cp -f video_engine/main/test/AutoTest/media/* /tmp/vie_auto_test' + ], + }, + ], + }], + ['OS=="win"', { + 'actions': [ + { + 'action_name': 'create vie test folder', + 'inputs': [ + 'media', + ], + 'outputs': [ + 'tmp/vie_auto_test/', + ], + 'action': [ + 'cmd', '/c', + 'mdkdir \\tmp\\vie_auto_test' + ], + }, + { + 'action_name': 'copy media files', + 'inputs': [ + 'media', + ], + 'outputs': [ + '\\tmp\\vie_auto_test\\*.jpg', + '\\tmp\\vie_auto_test\\*.yuv', + ], + 'action': [ + 'cmd', '/c', + 'xcopy /Y /R video_engine\\main\\test\\AutoTest\\media\\* \\tmp\\vie_auto_test' + ], + }, + ], + }], + ], #conditions + }, + ], +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/video_engine/main/test/SimpleCocoaGUI/GUI_Defines.h b/video_engine/main/test/SimpleCocoaGUI/GUI_Defines.h new file mode 100644 index 0000000000..83828441b9 --- /dev/null +++ b/video_engine/main/test/SimpleCocoaGUI/GUI_Defines.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * GUI_Defines.h + * + */ + + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_SIMPLECOCOAGUI_GUI_DEFINES_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_SIMPLECOCOAGUI_GUI_DEFINES_H_ + +#define ViE_TEST(x) if(-1 == x){ \ +int errNum = _ptrViEBase->LastError(); \ +NSLog(@"ERROR: %d at %s:%d", errNum, __FUNCTION__, __LINE__); \ +} + + +// Video Engine Related +#define V_CAPTURE_DEVICE_INDEX 0 +#define V_VIE_CAPTURE_ID 747 +#define V_DEVICE_NAME_LENGTH 256 +#define V_CODEC_INDEX 2 +#define V_IP_ADDRESS "127.0.0.1" +#define V_RTP_PORT 8000 + + + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_SIMPLECOCOAGUI_GUI_DEFINES_H_ diff --git a/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUI-Info.plist b/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUI-Info.plist new file mode 100644 index 0000000000..d0d3a18fe4 --- /dev/null +++ b/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUI-Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.yourcompany.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSMainNibFile + SimpleCocoaGUI + NSPrincipalClass + NSApplication + + diff --git a/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUIAppDelegate.h b/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUIAppDelegate.h new file mode 100644 index 0000000000..10d52fc5ec --- /dev/null +++ b/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUIAppDelegate.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// SimpleCocoaGUIAppDelegate.h +// + +#import +#include +using namespace std; + +@class ViECocoaRenderView; + +#include "GUI_Defines.h" + +#include "common_types.h" +#include "voe_base.h" + +#include "vie_base.h" +#include "vie_capture.h" +#include "vie_codec.h" +#include "vie_file.h" +#include "vie_network.h" +#include "vie_render.h" +#include "vie_rtp_rtcp.h" +#include "vie_errors.h" + + + +@interface SimpleCocoaGUIAppDelegate : NSObject { + NSWindow* _window; + IBOutlet NSOpenGLView* _vieCocoaRenderView1; + IBOutlet NSOpenGLView* _vieCocoaRenderView2; + IBOutlet NSButton* _butRestartLoopback; + VideoEngine* _ptrViE; + ViEBase* _ptrViEBase; + ViECapture* _ptrViECapture; + ViERender* _ptrViERender; + ViECodec* _ptrViECodec; + ViENetwork* _ptrViENetwork; + + bool _fullScreen; + int _videoChannel; + + int _captureId; + + VideoEngine* ptrViE; + ViEBase* ptrViEBase; + ViECapture* ptrViECapture; + ViERTP_RTCP* ptrViERtpRtcp; + ViERender* ptrViERender; + ViECodec* ptrViECodec; + ViENetwork* ptrViENetwork; +} + +@property (assign) IBOutlet NSWindow* window; +-(void)createUI:(bool)fullScreen; +-(void)initViECocoaTest; +-(void)initializeVariables; +-(void)NSLogVideoCodecs; +-(void)startViECocoaTest; +-(int)initLoopback; +-(int)ioLooback; +-(int)startLoopback; +-(int)stopLooback; + +-(IBAction)handleRestart:(id)sender; + + +@end diff --git a/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUIAppDelegate.mm b/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUIAppDelegate.mm new file mode 100644 index 0000000000..d594cfe1f3 --- /dev/null +++ b/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUIAppDelegate.mm @@ -0,0 +1,1075 @@ +// +// SimpleCocoaGUIAppDelegate.m +// + +#import "SimpleCocoaGUIAppDelegate.h" + +@implementation SimpleCocoaGUIAppDelegate + +@synthesize window = _window; + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + +// [self initializeVariables]; + [self createUI]; +// [self initViECocoaTest]; +// [self NSLogVideoCodecs]; +// [self startViECocoaTest]; + +// [self startLoopback]; + + [self ioLooback]; +} + +-(void)createUI{ + + NSRect outWindow1Frame = NSMakeRect(200, 200, 200, 200); + NSWindow* outWindow1 = [[NSWindow alloc] initWithContentRect:outWindow1Frame styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]; + [outWindow1 orderOut:nil]; + NSRect vieAutotestCocoaRenderView1Frame = NSMakeRect(0, 0, 200, 200); + _vieCocoaRenderView1 = [[ViECocoaRenderView alloc] initWithFrame:vieAutotestCocoaRenderView1Frame]; + [[outWindow1 contentView] addSubview:_vieCocoaRenderView1]; + [outWindow1 setTitle:[NSString stringWithFormat:@"window1"]]; + [outWindow1 makeKeyAndOrderFront:NSApp]; + + + NSRect outWindow2Frame = NSMakeRect(400, 200, 200, 200); + NSWindow* outWindow2 = [[NSWindow alloc] initWithContentRect:outWindow2Frame styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]; + [outWindow2 orderOut:nil]; + NSRect vieAutotestCocoaRenderView2Frame = NSMakeRect(0, 0, 200, 200); + _vieCocoaRenderView2 = [[ViECocoaRenderView alloc] initWithFrame:vieAutotestCocoaRenderView2Frame]; + [[outWindow2 contentView] addSubview:_vieCocoaRenderView2]; + [outWindow2 setTitle:[NSString stringWithFormat:@"window2"]]; + [outWindow2 makeKeyAndOrderFront:NSApp]; + + + + + + + +} + +-(void)initViECocoaTest{ + + int _error = 0; + _ptrViE = VideoEngine::Create(); + _ptrViEBase = ViEBase::GetInterface(_ptrViE); + _error = _ptrViEBase->Init(); + + _ptrViECapture = ViECapture::GetInterface(_ptrViE); + _ptrViERender = ViERender::GetInterface(_ptrViE); + _ptrViECodec = ViECodec::GetInterface(_ptrViE); + _ptrViENetwork = ViENetwork::GetInterface(_ptrViE); + + + _error = _ptrViE->SetTraceFile("ViEBaseStandardTest.txt"); + _error = _ptrViE->SetEncryptedTraceFile("ViEBaseStandardTestEncrypted.txt"); + + +} + + +-(void)initializeVariables{ + _fullScreen = YES; +} + +-(void)NSLogVideoCodecs{ + NSLog(@"Searching for video codecs....."); + + VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(VideoCodec)); + for(int index = 0; index < _ptrViECodec->NumberOfCodecs(); index++) + { + ViE_TEST(_ptrViECodec->GetCodec(index, videoCodec)); + NSLog(@"Video codec found: %s", videoCodec.plName); + } + +} +-(void)startViECocoaTest{ + + + + + int error=0; + + char deviceName[128]; + char deviceUniqueName[512]; + int captureId = 0; + int dummy = 0; + + //ViE_TEST(_ptrViEBase->CreateChannel(_videoChannel)); + //ViE_TEST(_ptrViECapture->GetCaptureDevice(0,deviceName,sizeof(deviceName),deviceUniqueName,sizeof(deviceUniqueName))); + //ViE_TEST(_ptrViECapture->AllocateCaptureDevice(deviceUniqueName,sizeof(deviceUniqueName),captureId)); + //ViE_TEST(_ptrViECapture->AllocateCaptureDevice("dummydevicethatdoesnotexist",sizeof(deviceUniqueName),dummy)); + + char captureDeviceName[V_DEVICE_NAME_LENGTH] = ""; + char captureDeviceUniqueId[V_DEVICE_NAME_LENGTH] = ""; + int captureDeviceId = 0; + + + + ViE_TEST(_ptrViE->SetTraceFilter(webrtc::TR_ALL)); + ViE_TEST(_ptrViE->SetTraceFile("ViECocoaTrace.txt")); + ViE_TEST(_ptrViE->SetEncryptedTraceFile("ViECocoaEncryptedTrace.txt")); + + + + + // base + ViE_TEST(_ptrViEBase->CreateChannel(_videoChannel)); + + // capture device + ViE_TEST(_ptrViECapture->GetCaptureDevice(V_CAPTURE_DEVICE_INDEX, captureDeviceName, V_DEVICE_NAME_LENGTH, captureDeviceUniqueId, V_DEVICE_NAME_LENGTH)); + ViE_TEST(_ptrViECapture->AllocateCaptureDevice(captureDeviceUniqueId, V_DEVICE_NAME_LENGTH, captureDeviceId)); + ViE_TEST(_ptrViECapture->ConnectCaptureDevice(captureDeviceId, _videoChannel)); + ViE_TEST(_ptrViECapture->StartCapture(captureDeviceId)); + + // renderer + ViE_TEST(_ptrViERender->AddRenderer(captureDeviceId, (void*)_vieCocoaRenderView1, 0, 0.0, 0.0, 1.0, 1.0)); + ViE_TEST(_ptrViERender->StartRender(captureDeviceId)); +// usleep(3 * 1000); +// ViE_TEST(_ptrViERender->RemoveRenderer(captureDeviceId)); + //exit(0); + + +// // codec +// [self NSLogVideoCodecs]; +// VideoCodec videoCodec; +// memset(&videoCodec, 0, sizeof(VideoCodec)); +// ViE_TEST(_ptrViECodec->GetCodec(V_CODEC_INDEX, videoCodec)); +// ViE_TEST(_ptrViECodec->SetReceiveCodec(_videoChannel, videoCodec)); +// ViE_TEST(_ptrViECodec->SetSendCodec(_videoChannel, videoCodec)); +// +// // network + base +// ViE_TEST(_ptrViENetwork->SetLocalReceiver(_videoChannel, V_RTP_PORT)); +// ViE_TEST(_ptrViEBase->StartReceive(_videoChannel)); +// ViE_TEST(_ptrViENetwork->SetSendDestination(_videoChannel, V_IP_ADDRESS, V_RTP_PORT)); +// ViE_TEST(_ptrViEBase->StartSend(_videoChannel)); +// ViE_TEST(_ptrViERender->MirrorRenderStream(captureDeviceId, true, false, true)); + + +} + +-(int)initLoopback +{ + +} +-(int)startLoopback +{ + //******************************************************** + // Begin create/initialize Video Engine for testing + //******************************************************** + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + std::string str; + + // + // Create a VideoEngine instance + // +// VideoEngine* ptrViE = NULL; + ptrViE = VideoEngine::Create(); + if (ptrViE == NULL) + { + printf("ERROR in VideoEngine::Create\n"); + return -1; + } + + error = ptrViE->SetTraceFilter(webrtc::TR_ALL); + if (error == -1) + { + printf("ERROR in VideoEngine::SetTraceLevel\n"); + return -1; + } + + + error = ptrViE->SetTraceFile("ViETrace.txt"); + if (error == -1) + { + printf("ERROR in VideoEngine::SetTraceFile\n"); + return -1; + } + + error = ptrViE->SetEncryptedTraceFile("ViEEncryptedTrace.txt"); + if (error == -1) + { + printf("ERROR in VideoEngine::SetEncryptedTraceFile\n"); + return -1; + } + + // + // Init VideoEngine and create a channel + // + ptrViEBase = ViEBase::GetInterface(ptrViE); + if (ptrViEBase == NULL) + { + printf("ERROR in ViEBase::GetInterface\n"); + return -1; + } + + error = ptrViEBase->Init(); + if (error == -1) + { + printf("ERROR in ViEBase::Init\n"); + return -1; + } + + int videoChannel = -1; + error = ptrViEBase->CreateChannel(_videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::CreateChannel\n"); + return -1; + } + + // + // List available capture devices, allocate and connect. + // + ptrViECapture = ViECapture::GetInterface(ptrViE); + if (ptrViEBase == NULL) + { + printf("ERROR in ViECapture::GetInterface\n"); + return -1; + } + + const unsigned int KMaxDeviceNameLength = 128; + const unsigned int KMaxUniqueIdLength = 256; + char deviceName[KMaxDeviceNameLength]; + memset(deviceName, 0, KMaxDeviceNameLength); + char uniqueId[KMaxUniqueIdLength]; + memset(uniqueId, 0, KMaxUniqueIdLength); + + std::cout << std::endl; + std::cout << "Available capture devices:" << std::endl; + unsigned int captureIdx = 0; + for (captureIdx = 0; + captureIdx < ptrViECapture->NumberOfCaptureDevices(); + captureIdx++) + { + memset(deviceName, 0, KMaxDeviceNameLength); + memset(uniqueId, 0, KMaxUniqueIdLength); + + error = ptrViECapture->GetCaptureDevice(captureIdx, + deviceName, KMaxDeviceNameLength, uniqueId, KMaxUniqueIdLength); + if (error == -1) + { + printf("ERROR in ViECapture::GetCaptureDevice\n"); + return -1; + } + std::cout << " " << captureIdx+1 << ". " << deviceName + << std::endl; + } + std::cout << std::endl; + std::cout << "Choose capture devices: "; +// std::getline(std::cin, str); +// captureIdx = atoi(str.c_str()) - 1; + captureIdx = 0; + error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName, + KMaxDeviceNameLength, uniqueId, KMaxUniqueIdLength); + if (error == -1) + { + printf("ERROR in ViECapture::GetCaptureDevice\n"); + return -1; + } + + _captureId = 0; + error = ptrViECapture->AllocateCaptureDevice(uniqueId, + KMaxUniqueIdLength, _captureId); + if (error == -1) + { + printf("ERROR in ViECapture::AllocateCaptureDevice\n"); + return -1; + } + + error = ptrViECapture->ConnectCaptureDevice(_captureId, + _videoChannel); + if (error == -1) + { + printf("ERROR in ViECapture::ConnectCaptureDevice\n"); + return -1; + } + + error = ptrViECapture->StartCapture(_captureId); + if (error == -1) + { + printf("ERROR in ViECapture::StartCapture\n"); + return -1; + } + + // + // RTP/RTCP settings + // + ptrViERtpRtcp = ViERTP_RTCP::GetInterface(ptrViE); + if (ptrViERtpRtcp == NULL) + { + printf("ERROR in ViERTP_RTCP::GetInterface\n"); + return -1; + } + + error = ptrViERtpRtcp->SetRTCPStatus(_videoChannel, + kRtcpCompound_RFC4585); + if (error == -1) + { + printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n"); + return -1; + } + + error = ptrViERtpRtcp->SetKeyFrameRequestMethod(_videoChannel, + kViEKeyFrameRequestPliRtcp); + if (error == -1) + { + printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n"); + return -1; + } + + error = ptrViERtpRtcp->SetTMMBRStatus(_videoChannel, true); + if (error == -1) + { + printf("ERROR in ViERTP_RTCP::SetTMMBRStatus\n"); + return -1; + } + + // + // Set up rendering + // + ptrViERender = ViERender::GetInterface(ptrViE); + if (ptrViERender == NULL) + { + printf("ERROR in ViERender::GetInterface\n"); + return -1; + } + + error = ptrViERender->AddRenderer(_captureId, _vieCocoaRenderView1, + 0, 0.0, 0.0, 1.0, 1.0); + if (error == -1) + { + printf("ERROR in ViERender::AddRenderer\n"); + return -1; + } + + error = ptrViERender->StartRender(_captureId); + if (error == -1) + { + printf("ERROR in ViERender::StartRender\n"); + return -1; + } + + error = ptrViERender->AddRenderer(_videoChannel, _vieCocoaRenderView2, + 1, 0.0, 0.0, 1.0, 1.0); + if (error == -1) + { + printf("ERROR in ViERender::AddRenderer\n"); + return -1; + } + + error = ptrViERender->StartRender(_videoChannel); + if (error == -1) + { + printf("ERROR in ViERender::StartRender\n"); + return -1; + } + + // + // Setup codecs + // + ptrViECodec = ViECodec::GetInterface(ptrViE); + if (ptrViECodec == NULL) + { + printf("ERROR in ViECodec::GetInterface\n"); + return -1; + } + + std::cout << std::endl; + std::cout << "Available codecs:" << std::endl; + + // Check available codecs and prepare receive codecs + VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(VideoCodec)); + unsigned int codecIdx = 0; + for (codecIdx = 0; + codecIdx < ptrViECodec->NumberOfCodecs(); + codecIdx++) + { + error = ptrViECodec->GetCodec(codecIdx, videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::GetCodec\n"); + return -1; + } + + error = ptrViECodec->SetReceiveCodec(_videoChannel, + videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::SetReceiveCodec\n"); + return -1; + } + if (videoCodec.codecType != kVideoCodecRED && + videoCodec.codecType != kVideoCodecULPFEC) + { + std::cout << " " << codecIdx+1 << ". " << videoCodec.plName + << std::endl; + } + } +// std::cout << std::endl; +// std::cout << "Choose codec: "; +// std::getline(std::cin, str); +// codecIdx = atoi(str.c_str()) - 1; + codecIdx = 0; + + error = ptrViECodec->GetCodec(codecIdx, videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::GetCodec\n"); + return -1; + } + + error = ptrViECodec->SetSendCodec(_videoChannel, videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::SetSendCodec\n"); + return -1; + } + + // + // Address settings + // + ptrViENetwork = ViENetwork::GetInterface(ptrViE); + if (ptrViENetwork == NULL) + { + printf("ERROR in ViENetwork::GetInterface\n"); + return -1; + } + + const char* ipAddress = "127.0.0.1"; + const unsigned short rtpPort = 6000; + error = ptrViENetwork->SetLocalReceiver(_videoChannel, rtpPort); + if (error == -1) + { + printf("ERROR in ViENetwork::SetLocalReceiver\n"); + return -1; + } + + error = ptrViEBase->StartReceive(_videoChannel); + if (error == -1) + { + printf("ERROR in ViENetwork::StartReceive\n"); + return -1; + } + + error = ptrViENetwork->SetSendDestination(_videoChannel, + ipAddress, rtpPort); + if (error == -1) + { + printf("ERROR in ViENetwork::SetSendDestination\n"); + return -1; + } + + error = ptrViEBase->StartSend(_videoChannel); + if (error == -1) + { + printf("ERROR in ViENetwork::StartSend\n"); + return -1; + } + + + //******************************************************** + // Engine started + //******************************************************** + + + // Call started + std::cout << std::endl; + std::cout << "Loopback call started" << std::endl; +// std::cout << std::endl << std::endl; +// std::cout << "Press enter to stop..."; +// std::getline(std::cin, str); +} + +-(int)stopLooback +{ + int error = 0; + + + + //******************************************************** + // Testing finished. Tear down Video Engine + //******************************************************** + + error = ptrViEBase->StopReceive(_videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::StopReceive\n"); + return -1; + } + + error = ptrViEBase->StopSend(_videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::StopSend\n"); + return -1; + } + + error = ptrViERender->StopRender(_captureId); + if (error == -1) + { + printf("ERROR in ViERender::StopRender\n"); + return -1; + } + + error = ptrViERender->RemoveRenderer(_captureId); + if (error == -1) + { + printf("ERROR in ViERender::RemoveRenderer\n"); + return -1; + } + + error = ptrViERender->StopRender(_videoChannel); + if (error == -1) + { + printf("ERROR in ViERender::StopRender\n"); + return -1; + } + + error = ptrViERender->RemoveRenderer(_videoChannel); + if (error == -1) + { + printf("ERROR in ViERender::RemoveRenderer\n"); + return -1; + } + + error = ptrViECapture->StopCapture(_captureId); + if (error == -1) + { + printf("ERROR in ViECapture::StopCapture\n"); + return -1; + } + + error = ptrViECapture->DisconnectCaptureDevice(_videoChannel); + if (error == -1) + { + printf("ERROR in ViECapture::DisconnectCaptureDevice\n"); + return -1; + } + + error = ptrViECapture->ReleaseCaptureDevice(_captureId); + if (error == -1) + { + printf("ERROR in ViECapture::ReleaseCaptureDevice\n"); + return -1; + } + + error = ptrViEBase->DeleteChannel(_videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::DeleteChannel\n"); + return -1; + } + + int remainingInterfaces = 0; + remainingInterfaces = ptrViECodec->Release(); + remainingInterfaces += ptrViECapture->Release(); + remainingInterfaces += ptrViERtpRtcp->Release(); + remainingInterfaces += ptrViERender->Release(); + remainingInterfaces += ptrViENetwork->Release(); + remainingInterfaces += ptrViEBase->Release(); + if (remainingInterfaces > 0) + { + printf("ERROR: Could not release all interfaces\n"); + return -1; + } + + bool deleted = VideoEngine::Delete(ptrViE); + if (deleted == false) + { + printf("ERROR in VideoEngine::Delete\n"); + return -1; + } + + return 0; + + // =================================================================== + // + // END: VideoEngine 3.0 Sample Code + // + // =================================================================== + + +} + +-(int)ioLooback +{ + //******************************************************** + // Begin create/initialize Video Engine for testing + //******************************************************** + + int error = 0; + bool succeeded = true; + int numberOfErrors = 0; + std::string str; + + // + // Create a VideoEngine instance + // + VideoEngine* ptrViE = NULL; + ptrViE = VideoEngine::Create(); + if (ptrViE == NULL) + { + printf("ERROR in VideoEngine::Create\n"); + return -1; + } + + error = ptrViE->SetTraceFilter(webrtc::TR_ALL); + if (error == -1) + { + printf("ERROR in VideoEngine::SetTraceLevel\n"); + return -1; + } + + + error = ptrViE->SetTraceFile("ViETrace.txt"); + if (error == -1) + { + printf("ERROR in VideoEngine::SetTraceFile\n"); + return -1; + } + + error = ptrViE->SetEncryptedTraceFile("ViEEncryptedTrace.txt"); + if (error == -1) + { + printf("ERROR in VideoEngine::SetEncryptedTraceFile\n"); + return -1; + } + + // + // Init VideoEngine and create a channel + // + ViEBase* ptrViEBase = ViEBase::GetInterface(ptrViE); + if (ptrViEBase == NULL) + { + printf("ERROR in ViEBase::GetInterface\n"); + return -1; + } + + error = ptrViEBase->Init(); + if (error == -1) + { + printf("ERROR in ViEBase::Init\n"); + return -1; + } + + int videoChannel = -1; + error = ptrViEBase->CreateChannel(videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::CreateChannel\n"); + return -1; + } + + // + // List available capture devices, allocate and connect. + // + ViECapture* ptrViECapture = + ViECapture::GetInterface(ptrViE); + if (ptrViEBase == NULL) + { + printf("ERROR in ViECapture::GetInterface\n"); + return -1; + } + + const unsigned int KMaxDeviceNameLength = 128; + const unsigned int KMaxUniqueIdLength = 256; + char deviceName[KMaxDeviceNameLength]; + memset(deviceName, 0, KMaxDeviceNameLength); + char uniqueId[KMaxUniqueIdLength]; + memset(uniqueId, 0, KMaxUniqueIdLength); + + std::cout << std::endl; + std::cout << "Available capture devices:" << std::endl; + unsigned int captureIdx = 0; + for (captureIdx = 0; + captureIdx < ptrViECapture->NumberOfCaptureDevices(); + captureIdx++) + { + memset(deviceName, 0, KMaxDeviceNameLength); + memset(uniqueId, 0, KMaxUniqueIdLength); + + error = ptrViECapture->GetCaptureDevice(captureIdx, + deviceName, KMaxDeviceNameLength, uniqueId, KMaxUniqueIdLength); + if (error == -1) + { + printf("ERROR in ViECapture::GetCaptureDevice\n"); + return -1; + } + std::cout << " " << captureIdx+1 << ". " << deviceName + << std::endl; + } + std::cout << std::endl; + std::cout << "Choose capture devices: "; +// std::getline(std::cin, str); +// captureIdx = atoi(str.c_str()) - 1; + captureIdx = 0; + error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName, + KMaxDeviceNameLength, uniqueId, KMaxUniqueIdLength); + if (error == -1) + { + printf("ERROR in ViECapture::GetCaptureDevice\n"); + return -1; + } + + int captureId = 0; + error = ptrViECapture->AllocateCaptureDevice(uniqueId, + KMaxUniqueIdLength, captureId); + if (error == -1) + { + printf("ERROR in ViECapture::AllocateCaptureDevice\n"); + return -1; + } + + error = ptrViECapture->ConnectCaptureDevice(captureId, + videoChannel); + if (error == -1) + { + printf("ERROR in ViECapture::ConnectCaptureDevice\n"); + return -1; + } + + error = ptrViECapture->StartCapture(captureId); + if (error == -1) + { + printf("ERROR in ViECapture::StartCapture\n"); + return -1; + } + + // + // RTP/RTCP settings + // + ViERTP_RTCP* ptrViERtpRtcp = + ViERTP_RTCP::GetInterface(ptrViE); + if (ptrViERtpRtcp == NULL) + { + printf("ERROR in ViERTP_RTCP::GetInterface\n"); + return -1; + } + + error = ptrViERtpRtcp->SetRTCPStatus(videoChannel, + kRtcpCompound_RFC4585); + if (error == -1) + { + printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n"); + return -1; + } + + error = ptrViERtpRtcp->SetKeyFrameRequestMethod(videoChannel, + kViEKeyFrameRequestPliRtcp); + if (error == -1) + { + printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n"); + return -1; + } + + error = ptrViERtpRtcp->SetTMMBRStatus(videoChannel, true); + if (error == -1) + { + printf("ERROR in ViERTP_RTCP::SetTMMBRStatus\n"); + return -1; + } + + // + // Set up rendering + // + ViERender* ptrViERender = + ViERender::GetInterface(ptrViE); + if (ptrViERender == NULL) + { + printf("ERROR in ViERender::GetInterface\n"); + return -1; + } + +// error = ptrViERender->EnableFullScreenRender(_vieCocoaRenderView1); +// if (error == -1) +// { +// printf("ERROR in ViERender::AddRenderer\n"); +// return -1; +// } + + + error = ptrViERender->AddRenderer(captureId, _vieCocoaRenderView1, + 0, 0.5, 0.5, 1.0, 1.0); + if (error == -1) + { + printf("ERROR in ViERender::AddRenderer\n"); + return -1; + } + + error = ptrViERender->StartRender(captureId); + if (error == -1) + { + printf("ERROR in ViERender::StartRender\n"); + return -1; + } + + error = ptrViERender->AddRenderer(videoChannel, _vieCocoaRenderView2, + 1, 0.0, 0.0, 1.0, 1.0); + if (error == -1) + { + printf("ERROR in ViERender::AddRenderer\n"); + return -1; + } + + error = ptrViERender->StartRender(videoChannel); + if (error == -1) + { + printf("ERROR in ViERender::StartRender\n"); + return -1; + } + + // + // Setup codecs + // + ViECodec* ptrViECodec = ViECodec::GetInterface(ptrViE); + if (ptrViECodec == NULL) + { + printf("ERROR in ViECodec::GetInterface\n"); + return -1; + } + + std::cout << std::endl; + std::cout << "Available codecs:" << std::endl; + + // Check available codecs and prepare receive codecs + VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(VideoCodec)); + unsigned int codecIdx = 0; + for (codecIdx = 0; + codecIdx < ptrViECodec->NumberOfCodecs(); + codecIdx++) + { + error = ptrViECodec->GetCodec(codecIdx, videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::GetCodec\n"); + return -1; + } + + error = ptrViECodec->SetReceiveCodec(videoChannel, + videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::SetReceiveCodec\n"); + return -1; + } + if (videoCodec.codecType != kVideoCodecRED && + videoCodec.codecType != kVideoCodecULPFEC) + { + std::cout << " " << codecIdx+1 << ". " << videoCodec.plName + << std::endl; + } + } + std::cout << std::endl; + std::cout << "Choose codec: "; +// std::getline(std::cin, str); +// codecIdx = atoi(str.c_str()) - 1; + + + error = ptrViECapture->ShowCaptureSettingsDialogBox("unique",10, "mytitle"); + codecIdx = 0; + error = ptrViECodec->GetCodec(codecIdx, videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::GetCodec\n"); + return -1; + } + + error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); + if (error == -1) + { + printf("ERROR in ViECodec::SetSendCodec\n"); + return -1; + } + + // + // Address settings + // + ViENetwork* ptrViENetwork = + ViENetwork::GetInterface(ptrViE); + if (ptrViENetwork == NULL) + { + printf("ERROR in ViENetwork::GetInterface\n"); + return -1; + } + + const char* ipAddress = "127.0.0.1"; + const unsigned short rtpPort = 6000; + error = ptrViENetwork->SetLocalReceiver(videoChannel, rtpPort); + if (error == -1) + { + printf("ERROR in ViENetwork::SetLocalReceiver\n"); + return -1; + } + + error = ptrViEBase->StartReceive(videoChannel); + if (error == -1) + { + printf("ERROR in ViENetwork::StartReceive\n"); + return -1; + } + + error = ptrViENetwork->SetSendDestination(videoChannel, + ipAddress, rtpPort); + if (error == -1) + { + printf("ERROR in ViENetwork::SetSendDestination\n"); + return -1; + } + + error = ptrViEBase->StartSend(videoChannel); + if (error == -1) + { + printf("ERROR in ViENetwork::StartSend\n"); + return -1; + } + + + //******************************************************** + // Engine started + //******************************************************** + + + // Call started + std::cout << std::endl; + std::cout << "Loopback call started" << std::endl; + std::cout << std::endl << std::endl; + std::cout << "Press enter to stop..."; +// [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; +// std::getline(std::cin, str); + usleep(5 * 1000 * 1000); + + //int i = 0; +// while(1) +// { +// NSLog(@"app iteration %d", i); +// i++; +// [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; +// std::getline(std::cin, str); +// if(i > 3) +// { +// break; +// } +// } + + //******************************************************** + // Testing finished. Tear down Video Engine + //******************************************************** + + error = ptrViEBase->StopReceive(videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::StopReceive\n"); + return -1; + } + + error = ptrViEBase->StopSend(videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::StopSend\n"); + return -1; + } + + error = ptrViERender->StopRender(captureId); + if (error == -1) + { + printf("ERROR in ViERender::StopRender\n"); + return -1; + } + + error = ptrViERender->RemoveRenderer(captureId); + if (error == -1) + { + printf("ERROR in ViERender::RemoveRenderer\n"); + return -1; + } + + error = ptrViERender->StopRender(videoChannel); + if (error == -1) + { + printf("ERROR in ViERender::StopRender\n"); + return -1; + } + + error = ptrViERender->RemoveRenderer(videoChannel); + if (error == -1) + { + printf("ERROR in ViERender::RemoveRenderer\n"); + return -1; + } + + error = ptrViECapture->StopCapture(captureId); + if (error == -1) + { + printf("ERROR in ViECapture::StopCapture\n"); + return -1; + } + + error = ptrViECapture->DisconnectCaptureDevice(videoChannel); + if (error == -1) + { + printf("ERROR in ViECapture::DisconnectCaptureDevice\n"); + return -1; + } + + error = ptrViECapture->ReleaseCaptureDevice(captureId); + if (error == -1) + { + printf("ERROR in ViECapture::ReleaseCaptureDevice\n"); + return -1; + } + + error = ptrViEBase->DeleteChannel(videoChannel); + if (error == -1) + { + printf("ERROR in ViEBase::DeleteChannel\n"); + return -1; + } + + int remainingInterfaces = 0; + remainingInterfaces = ptrViECodec->Release(); + remainingInterfaces += ptrViECapture->Release(); + remainingInterfaces += ptrViERtpRtcp->Release(); + remainingInterfaces += ptrViERender->Release(); + remainingInterfaces += ptrViENetwork->Release(); + remainingInterfaces += ptrViEBase->Release(); + if (remainingInterfaces > 0) + { + printf("ERROR: Could not release all interfaces\n"); + return -1; + } + + bool deleted = VideoEngine::Delete(ptrViE); + if (deleted == false) + { + printf("ERROR in VideoEngine::Delete\n"); + return -1; + } + + NSLog(@"Finished function"); + return 0; + + // + // END: VideoEngine 3.0 Sample Code + // + // =================================================================== +} + + + + +-(IBAction)handleRestart:(id)sender +{ +// [self stopLooback]; +// [self startLoopback]; + [self ioLooback]; +} +@end diff --git a/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUI_Prefix.pch b/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUI_Prefix.pch new file mode 100644 index 0000000000..72b5870875 --- /dev/null +++ b/video_engine/main/test/SimpleCocoaGUI/SimpleCocoaGUI_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'SimpleCocoaGUI' target in the 'SimpleCocoaGUI' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/video_engine/main/test/SimpleCocoaGUI/main.m b/video_engine/main/test/SimpleCocoaGUI/main.m new file mode 100644 index 0000000000..9d52a1c3ce --- /dev/null +++ b/video_engine/main/test/SimpleCocoaGUI/main.m @@ -0,0 +1,12 @@ +// +// main.m +// SimpleCocoaGUI +// +// + +#import + +int main(int argc, char *argv[]) +{ + return NSApplicationMain(argc, (const char **) argv); +} diff --git a/video_engine/main/test/WindowsTest/Capture.rc b/video_engine/main/test/WindowsTest/Capture.rc new file mode 100644 index 0000000000..7ad089bd09 --- /dev/null +++ b/video_engine/main/test/WindowsTest/Capture.rc @@ -0,0 +1,254 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Korean resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_KOR) +#ifdef _WIN32 +LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT +#pragma code_page(949) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_KOR)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 18, 1\r\n" + "#pragma code_page(949)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\Capture.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""l.kor\\afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN +END + +#endif // Korean resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Swedish resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_SVE) +#ifdef _WIN32 +LANGUAGE LANG_SWEDISH, SUBLANG_DEFAULT +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_SLAVE_CHANNEL DIALOGEX 0, 0, 677, 358 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Slave channel" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_IPADDRESS1,"SysIPAddress32",WS_TABSTOP,485,18,105,15 + EDITTEXT IDC_LOCAL_PORT1,631,18,36,16,ES_AUTOHSCROLL + LTEXT "IP-address",IDC_STATIC,495,7,42,9 + LTEXT "Local Port",IDC_STATIC,633,7,37,9 + EDITTEXT IDC_REMOTE_PORT1,593,18,36,16,ES_AUTOHSCROLL + LTEXT "Port",IDC_STATIC,595,7,17,9 + CONTROL "Ext",IDC_EXTTRANSPORT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,489,41,29,12 + LTEXT "delay",IDC_STATIC,589,41,21,9 + COMBOBOX IDC_PACKETLOSS,535,40,45,82,CBS_DROPDOWN | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_DELAY,611,40,45,82,CBS_DROPDOWN | WS_DISABLED | WS_VSCROLL | WS_TABSTOP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_SLAVE_CHANNEL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 670 + TOPMARGIN, 7 + BOTTOMMARGIN, 351 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Swedish resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Neutral (Sys. Default) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DXQUALITY_DIALOG DIALOGEX 0, 0, 699, 385 +STYLE DS_ABSALIGN | DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_WINDOWEDGE | WS_EX_STATICEDGE | WS_EX_APPWINDOW | WS_EX_NOINHERITLAYOUT +CAPTION "webrtc ViE test program" +FONT 9, "Arial", 400, 0, 0x0 +BEGIN + PUSHBUTTON "Start Send",IDC_STARTSEND,589,270,50,19 + PUSHBUTTON "Stop Send",IDC_STOPSend,639,270,50,19 + PUSHBUTTON "Start Listen",IDC_STARTLISTEN,589,291,50,19 + PUSHBUTTON "StopListen",IDC_STOPLISTEN,639,291,50,19 + CONTROL "",IDC_LIVEVIDEO,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_SUNKEN,450,179,139,101 + COMBOBOX IDC_DEVICE,487,14,185,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + CTEXT "Select Capture Device",IDC_STATIC,485,7,78,8 + COMBOBOX IDC_CODEC_LIST,490,90,58,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Codec",IDC_STATIC,490,82,21,8 + COMBOBOX IDC_CODEC_SIZE,627,90,62,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Codec Size",IDC_STATIC,611,82,36,8 + CONTROL "",IDC_IPADDRESS1,"SysIPAddress32",WS_TABSTOP,490,46,90,13 + EDITTEXT IDC_LOCAL_PORT1,615,46,31,14,ES_AUTOHSCROLL + LTEXT "IP-address",IDC_STATIC,498,37,36,8 + LTEXT "Local Port",IDC_STATIC,616,36,32,8 + LTEXT "Start Bitrate",IDC_STATIC,553,80,37,8 + COMBOBOX IDC_BITRATE,558,90,49,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_REMOTE_PORT1,582,46,31,14,ES_AUTOHSCROLL + LTEXT "Port",IDC_STATIC,584,37,14,8 + GROUPBOX "Remote client 1",IDC_STATIC,487,27,203,50 + LTEXT "Min FrameRate",IDC_STATIC,488,106,49,8 + COMBOBOX IDC_MIN_FRAME_RATE,488,115,48,82,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_CAPTURE,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,7,7,418,276 + CONTROL "TMMBR",IDC_TMMBR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,639,159,40,10 + GROUPBOX "Standard Protection",IDC_STATIC,566,133,72,41 + CONTROL "None",IDC_PROT_NONE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,579,141,33,10 + CONTROL "NACK",IDC_PROT_NACK,"Button",BS_AUTORADIOBUTTON,579,163,35,10 + CONTROL "FEC",IDC_PROT_FEC,"Button",BS_AUTORADIOBUTTON,579,152,30,10 + COMBOBOX IDC_RTCPMODE,571,119,80,57,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "RTCP Mode",IDC_STATIC,571,110,39,8 + LISTBOX IDC_INFORMATION,476,309,214,63,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_PACKETBURST,653,118,36,57,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Packet Burst",IDC_STATIC,649,109,40,8 + CONTROL "Stop Log",IDC_FREEZELOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,465,292,44,10 + PUSHBUTTON "Camera Cap",IDC_CAMERACAP,530,291,55,16 + CONTROL "Ext",IDC_EXTTRANSPORT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,493,66,25,10 + LTEXT "loss",IDC_STATIC,519,66,15,8 + LTEXT "delay",IDC_STATIC,578,66,18,8 + COMBOBOX IDC_PACKETLOSS,533,65,38,82,CBS_DROPDOWN | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_DELAY,598,65,38,82,CBS_DROPDOWN | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Record Incoming",IDC_BTN_RECORD_INCOMING,587,198,69,14 + PUSHBUTTON "Record outgoing",IDC_BTN_RECORD_OUTGOING,587,212,69,14 + PUSHBUTTON "Create Slave",IDC_BTN_CREATE_SLAVE,586,231,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DXQUALITY_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 690 + VERTGUIDE, 321 + VERTGUIDE, 372 + VERTGUIDE, 425 + VERTGUIDE, 465 + TOPMARGIN, 7 + BOTTOMMARGIN, 372 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Neutral (Sys. Default) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_KOR) +#ifdef _WIN32 +LANGUAGE 18, 1 +#pragma code_page(949) +#endif //_WIN32 +#include "res\Capture.rc2" // non-Microsoft Visual C++ edited resources +#include "l.kor\afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/video_engine/main/test/WindowsTest/CaptureDevicePool.cpp b/video_engine/main/test/WindowsTest/CaptureDevicePool.cpp new file mode 100644 index 0000000000..8f7c9a2d7f --- /dev/null +++ b/video_engine/main/test/WindowsTest/CaptureDevicePool.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "CaptureDevicePool.h" +#include "map_wrapper.h" +#include +#include +#include "critical_section_wrapper.h" +#include "vie_file.h" + +CaptureDevicePool::CaptureDevicePool(VideoEngine* videoEngine): +_critSect(*CriticalSectionWrapper::CreateCriticalSection()), +_vieCapture(ViECapture::GetInterface(videoEngine)), +_vieFile(ViEFile::GetInterface(videoEngine)) +{ +} + +CaptureDevicePool::~CaptureDevicePool(void) +{ + assert(_deviceMap.Size()==0); + _vieCapture->Release(); + _vieFile->Release(); + delete &_critSect; +} + +WebRtc_Word32 CaptureDevicePool::GetCaptureDevice(int& captureId, const char* uniqeDeviceName) +{ + CriticalSectionScoped cs(_critSect); + DeviceItem* device=NULL; + + for(MapItem* item=_deviceMap.First(); + item!=NULL; + item=_deviceMap.Next(item)) + { + //Found the device? + if(strcmp(uniqeDeviceName,(static_cast( item->GetItem()))->uniqeDeviceName)==0) + { + device=static_cast( item->GetItem()); + device->refCount++; + captureId=device->captureId; + return 0; + } + } + device = new DeviceItem; + strncpy(device->uniqeDeviceName,uniqeDeviceName,255); + + + // Device does not exist. Create it. + WebRtc_Word32 result=_vieCapture->AllocateCaptureDevice(device->uniqeDeviceName,strlen(device->uniqeDeviceName),device->captureId); + if(result==0) + { + //CaptureCapability cap; + /*cap.height=1080; + cap.width=1920; + cap.maxFPS=25; + cap.interlaced=true;*/ + // result=_vieCapture->StartCapture(device->captureId,cap); + result=_vieFile->SetCaptureDeviceImage(device->captureId,"captureDeviceImage.jpg"); + } + captureId=device->captureId; + _deviceMap.Insert(captureId,device); + device->refCount++; + + return result; + + +} +WebRtc_Word32 CaptureDevicePool::ReturnCaptureDevice(int captureId) +{ + CriticalSectionScoped cs(_critSect); + + MapItem* mapItem=_deviceMap.Find(captureId); + if(!mapItem) + return -1; + + DeviceItem* item=static_cast (mapItem->GetItem()); + if(!item) + return 0; + item->refCount--; + WebRtc_Word32 result=0; + + if(item->refCount==0) + { + result=_vieCapture->ReleaseCaptureDevice(captureId); + + _deviceMap.Erase(mapItem); + delete item; + + } + return result; +} diff --git a/video_engine/main/test/WindowsTest/CaptureDevicePool.h b/video_engine/main/test/WindowsTest/CaptureDevicePool.h new file mode 100644 index 0000000000..104b84f72b --- /dev/null +++ b/video_engine/main/test/WindowsTest/CaptureDevicePool.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#pragma once + +#include "common_types.h" + +#include "vie_base.h" +#include "vie_capture.h" +#include "vie_file.h" +#include "map_wrapper.h" + +namespace webrtc { +class CriticalSectionWrapper; +} +using namespace webrtc; +class CaptureDevicePool +{ +public: + CaptureDevicePool(VideoEngine* videoEngine); + ~CaptureDevicePool(void); + WebRtc_Word32 GetCaptureDevice(int& captureId, const char uniqeDeviceName[256]); + WebRtc_Word32 ReturnCaptureDevice(int captureId); + + private: + struct DeviceItem + { + int captureId; + WebRtc_Word32 refCount; + char uniqeDeviceName[256]; + DeviceItem() + { + captureId=-1; + refCount=0; + } + }; + CriticalSectionWrapper& _critSect; + ViECapture* _vieCapture; + ViEFile* _vieFile; + MapWrapper _deviceMap; + +}; diff --git a/video_engine/main/test/WindowsTest/ChannelDlg.cpp b/video_engine/main/test/WindowsTest/ChannelDlg.cpp new file mode 100644 index 0000000000..cea17c16fa --- /dev/null +++ b/video_engine/main/test/WindowsTest/ChannelDlg.cpp @@ -0,0 +1,1279 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "ChannelDlg.h" +#include "VideoSize.h" +#include "CaptureDevicePool.h" +#include "ChannelPool.h" + +#include +#include + + +#include "assert.h" + + +#include // threads. + +#if defined _WIN32 + #define SLEEP_10_SEC ::Sleep(10000) + #define GET_TIME_IN_MS timeGetTime +#endif + + +// Hack to convert char to TCHAR, using two buffers to be able to +// call twice in the same statement +TCHAR convertTemp1[256] = {0}; +TCHAR convertTemp2[256] = {0}; +bool convertBufferSwitch(false); +TCHAR* CharToTchar(const char* str, int len) +{ +#ifdef _UNICODE + TCHAR* temp = convertBufferSwitch ? convertTemp1 : convertTemp2; + convertBufferSwitch = !convertBufferSwitch; + memset(temp, 0, sizeof(convertTemp1)); + MultiByteToWideChar(CP_UTF8, 0, str, len, temp, 256); + return temp; +#else + return str; +#endif +} + +// Hack to convert TCHAR to char +char convertTemp3[256] = {0}; +char* TcharToChar(TCHAR* str, int len) +{ +#ifdef _UNICODE + memset(convertTemp3, 0, sizeof(convertTemp3)); + WideCharToMultiByte(CP_UTF8, 0, str, len, convertTemp3, 256, 0, 0); + return convertTemp3; +#else + return str; +#endif +} + +///////////////////////////////////////////////////////////////////////////// +// CDXChannelDlg dialog + +CDXChannelDlg::CDXChannelDlg(VideoEngine* videoEngine, + CaptureDevicePool& captureDevicePool, + ChannelPool& channelPool, + void* voiceEngine + ,CWnd* pParent,CDXChannelDlgObserver* observer, + int parentChannel/*=-1*/) + : CDialog(CDXChannelDlg::IDD, pParent), + _canAddLog(true), + _dialogObserver(observer), + _videoEngine(videoEngine), + _captureDevicePool(captureDevicePool), + _channelPool(channelPool), + _parentChannel(parentChannel), +#ifndef NO_VOICE_ENGINE + _voiceEngine((VoiceEngine*) voiceEngine), +#endif + _callbackEvent(::CreateEvent( NULL, FALSE, FALSE, NULL)), + _externalTransport(NULL) +{ + strcpy(_logMsg,""); + _channelId = -1; + _audioChannel=-1; + _captureId=-1; + + //_transport = NULL; + + + //{{AFX_DATA_INIT(CDXChannelDlg) + //}}AFX_DATA_INIT + // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 + + InitializeCriticalSection(&_critCallback); + unsigned int threadID; + _callbackThread=(HANDLE)_beginthreadex(NULL,1024*1024,CallbackThread,(void*)this,0, &threadID); + + +} + +void CDXChannelDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CDXChannelDlg) + DDX_Control(pDX, IDC_DEVICE, m_ctrlDevice); + DDX_Control(pDX, IDC_CODEC_LIST, m_ctrlCodec); + DDX_Control(pDX, IDC_CAPTURE, m_ctrlLiveRemoteVideo); + DDX_Control(pDX, IDC_LIVEVIDEO, m_ctrlLiveVideo); + DDX_Control(pDX, IDC_LOCAL_PORT1, m_localPort1); + DDX_Control(pDX, IDC_REMOTE_PORT1, m_remotePort1); + DDX_Control(pDX, IDC_IPADDRESS1, m_remoteIp1); + DDX_Control(pDX, IDC_CODEC_SIZE, m_ctrlCodecSize); + DDX_Control(pDX, IDC_RTCPMODE, m_ctrlRtcpMode); + DDX_Control(pDX, IDC_PACKETBURST, m_ctrlPacketBurst); + DDX_Control(pDX, IDC_BITRATE, m_ctrlBitrate); + DDX_Control(pDX, IDC_MIN_FRAME_RATE, m_ctrlMinFrameRate); + DDX_Control(pDX, IDC_TMMBR,m_cbTmmbr); + DDX_Control(pDX, IDC_EXTTRANSPORT,m_cbExternalTransport); + DDX_Control(pDX, IDC_PACKETLOSS,m_ctrlPacketLoss); + DDX_Control(pDX, IDC_DELAY,m_ctrlDelay); + DDX_Control(pDX, IDC_FREEZELOG,m_cbFreezeLog); + DDX_Control(pDX,IDC_INFORMATION,m_ctrlInfo); + //}}AFX_DATA_MAP +} + +// ON_WM_SYSKEYDOWN ALT+key + +BEGIN_MESSAGE_MAP(CDXChannelDlg, CDialog) + //{{AFX_MSG_MAP(CDXChannelDlg) + ON_WM_SYSCOMMAND() + ON_WM_RBUTTONUP() + //ON_WM_DEVICECHANGE() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_STARTSEND, OnStartSend) + ON_BN_CLICKED(IDC_STOPSend, OnStopSend) + //ON_WM_TIMER() + ON_WM_DESTROY() + //}}AFX_MSG_MAP + ON_CBN_SELCHANGE(IDC_CODEC_LIST, OnCbnSelchangeCodecList) + ON_CBN_SELCHANGE(IDC_DEVICE, OnCbnSelchangeDevice) + ON_CBN_SELCHANGE(IDC_CODEC_SIZE, OnCbnSelchangeSize) + ON_CBN_SELCHANGE(IDC_BITRATE, OnCbnSelchangeBitrate) + //ON_MESSAGE(WM_DISPLAYCHANGE, OnDisplayChange) + ON_CBN_SELCHANGE(IDC_MIN_FRAME_RATE, OnCbnSelchangeMinFrameRate) + ON_BN_CLICKED(IDC_STARTLISTEN, OnBnClickedStartlisten) + ON_BN_CLICKED(IDC_STOPLISTEN, OnBnClickedStoplisten) + ON_BN_CLICKED(IDC_TMMBR, &CDXChannelDlg::OnBnClickedTmmbr) + ON_CBN_SELCHANGE(IDC_RTCPMODE, &CDXChannelDlg::OnCbnSelchangeRtcpmode) + ON_BN_CLICKED(IDC_PROT_NACK, &CDXChannelDlg::OnBnClickedProtNack) + ON_BN_CLICKED(IDC_PROT_NONE, &CDXChannelDlg::OnBnClickedProtNone) + ON_BN_CLICKED(IDC_PROT_FEC, &CDXChannelDlg::OnBnClickedProtFec) + ON_BN_CLICKED(IDC_FREEZELOG, &CDXChannelDlg::OnBnClickedFreezelog) + ON_BN_CLICKED(IDC_CAMERACAP, &CDXChannelDlg::OnBnClickedCameracap) + ON_BN_CLICKED(IDC_EXTTRANSPORT, &CDXChannelDlg::OnBnClickedExttransport) + ON_CBN_SELCHANGE(IDC_PACKETLOSS, &CDXChannelDlg::OnCbnSelchangePacketloss) + ON_CBN_SELCHANGE(IDC_DELAY, &CDXChannelDlg::OnCbnSelchangeDelay) + ON_BN_CLICKED(IDC_BTN_RECORD_INCOMING, &CDXChannelDlg::OnBnClickedBtnRecordIncoming) + ON_BN_CLICKED(IDC_BTN_RECORD_OUTGOING, &CDXChannelDlg::OnBnClickedBtnRecordOutgoing) + ON_BN_CLICKED(IDC_BTN_CREATE_SLAVE, &CDXChannelDlg::OnBnClickedBtnCreateSlave) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CDXChannelDlg message handlers + + +BOOL CDXChannelDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Set the icon for this dialog. The framework does this automatically + // when the application's main window is not a dialog + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("5")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("6")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("7")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("8")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("9")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("10")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("11")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("12")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("13")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("14")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("15")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("16")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("17")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("18")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("19")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("20")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("21")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("22")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("23")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("24")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("25")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("26")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("27")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("28")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("29")); + ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("30")); + m_ctrlMinFrameRate.SetCurSel(25); + + // Codec sizes + for(VideoSize i=VideoSize::UNDEFINED;iSetVoiceEngine(_voiceEngine),-5); +#endif + + int err = 0; + + char str[64]; + bool found = false; + + + int captureIdx = 0; + while (-1 !=_vieCapture->GetCaptureDevice(captureIdx,str,sizeof(str),NULL,0)) + { + char* tmp = strstr(str,"(VFW)"); + if (!tmp) + { + ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)CharToTchar(str,-1)); + found = true; + } + captureIdx++; + memset(str, 0, 64); + } + WIN32_FIND_DATA FindFileData; + HANDLE hFind; + //char fileSearch[256]; + //strcpy(fileSearch,_T("*.avi")); + hFind = FindFirstFile(_T("*.avi"), &FindFileData); + if (hFind != INVALID_HANDLE_VALUE) + { + + ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)(FindFileData.cFileName)); + while(FindNextFile(hFind,&FindFileData)) + { + ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)(FindFileData.cFileName)); + } + FindClose(hFind); + } + + + + ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("Conference")); + ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("None")); + + if (!found) + { + strncpy(str,"N/A",64); + ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)CharToTchar(str,-1)); + } + m_ctrlDevice.SetCurSel(0); + + //Codecs + int numOfCodecs = _vieCodec->NumberOfCodecs(); + for(int i=0; iGetCodec(i,codec)) + { + ::SendMessage(m_ctrlCodec.m_hWnd, CB_ADDSTRING, 0,(LPARAM)CharToTchar(codec.plName,-1)); + } + } + m_ctrlCodec.SetCurSel(0); + +#ifndef NO_VOICE_ENGINE + CodecInst voiceCodec; + int numOfVeCodecs = _veCodec->NumOfCodecs(); + for(int i=0; iGetCodec(i,voiceCodec)!=-1) + { + if(strncmp(voiceCodec.plname,"ISAC",4)==0) + break; + + + } + } + + _audioChannel = _veBase->CreateChannel(); + + + TEST_MUSTPASS(_veRTCP->SetRTCPStatus(_audioChannel, true),-5); + TEST_MUSTPASS(_veCodec->SetSendCodec(_audioChannel, voiceCodec),-5); + TEST_MUSTPASS(_veBase->StartPlayout(_audioChannel),-5); + +#endif //NO_VOICE_ENGINE + + if(_parentChannel==-1) + { + TEST_MUSTPASS(_vieBase->CreateChannel(_channelId),-5); + } + else // This is a slave channel + { + TEST_MUSTPASS(_vieBase->CreateChannel(_channelId,_parentChannel),-5); + } +#ifndef NO_VOICE_ENGINE + TEST_MUSTPASS(_vieBase->ConnectAudioChannel(_channelId,_audioChannel),-5); +#endif + + _channelPool.AddChannel(_channelId); + + //Set Receive codec + { + VideoCodec codec; + int numOfCodecs = _vieCodec->NumberOfCodecs();; + for(int i=0; iGetCodec(i,codec)) + { + if(codec.codecType == webrtc::kVideoCodecVP8) + { + codec.codecSpecific.VP8.feedbackModeOn = true; + codec.codecSpecific.VP8.pictureLossIndicationOn = true; + } + TEST_MUSTPASS(_vieCodec->SetReceiveCodec(_channelId,codec),-5); + } + } + } + + //TMMBR + m_cbTmmbr.SetCheck(BST_CHECKED); + OnBnClickedTmmbr(); + + //Packet Burst + m_ctrlPacketBurst.SetCurSel(0); + + + //Protection method none + CButton *opProtection = (CButton *) GetDlgItem(IDC_PROT_NONE); + opProtection->SetCheck(BST_CHECKED); + OnBnClickedProtNone(); + + + // Configure the renderer + ConfigureRender(); + + TEST_MUSTPASS(_vieCodec->RegisterEncoderObserver(_channelId,*this),kViECodecObserverAlreadyRegistered); + TEST_MUSTPASS(_vieCodec->RegisterDecoderObserver(_channelId,*this),-5); + + TEST_MUSTPASS(_vieBase->RegisterObserver(*this),kViEBaseObserverAlreadyRegistered); + + + + + //Set captions based on channel id + m_remoteIp1.SetAddress(127,0,0,1); + CString port; + port.AppendFormat(_T("%d"),11111+_channelId*4); + m_remotePort1.SetWindowText(port); + m_localPort1.SetWindowText(port); + + CString title; + this->GetWindowText(title); + if(_parentChannel==-1) + { + title.AppendFormat(_T("%s - channel %d"),title,_channelId); + } + else + { + title.AppendFormat(_T("%s - slave channel %d - parent %d"),title,_channelId,_parentChannel); + } + this->SetWindowText(title); + + if(_parentChannel!=-1) + m_ctrlDevice.EnableWindow(FALSE); //Prevent from changing capture device + + return TRUE; // return TRUE unless you set the focus to a control +} + + + +void CDXChannelDlg::OnTimer(UINT nIDEvent) +{ + CDialog::OnTimer(nIDEvent); +} + +void CDXChannelDlg::SetSendCodec() +{ + // Get the codec stucture + int codecSel= m_ctrlCodec.GetCurSel(); + VideoCodec codec; + TEST_MUSTPASS(_vieCodec->GetCodec(codecSel,codec),-5); + + + // Set Codec Size + VideoSize sizeSel=VideoSize(m_ctrlCodecSize.GetCurSel()); + int width, height; + GetWidthHeight(sizeSel, width, height); + codec.width=width; + codec.height=height; + + //Set the codec bitrate + CString bitrateStr; + m_ctrlBitrate.GetLBText(m_ctrlBitrate.GetCurSel(), bitrateStr); + int bitrate = _ttoi(bitrateStr.GetBuffer(0)); + if(codec.codecType!=kVideoCodecI420) + { + codec.startBitrate=bitrate; + codec.maxBitrate=bitrate*4; + } + + + //Set the codec frame rate + codec.maxFramerate = m_ctrlMinFrameRate.GetCurSel() +5; + + if(strncmp(codec.plName, "VP8", 5) == 0) + { + codec.codecSpecific.VP8.feedbackModeOn = true; + codec.codecSpecific.VP8.pictureLossIndicationOn = true; + TEST_MUSTPASS(_vieRTPRTCP->SetKeyFrameRequestMethod(_channelId, kViEKeyFrameRequestPliRtcp),-5); + }else + { + TEST_MUSTPASS(_vieRTPRTCP->SetKeyFrameRequestMethod(_channelId, kViEKeyFrameRequestPliRtcp),-5); + } + TEST_MUSTPASS(_vieCodec->SetSendCodec(_channelId, codec),-5); + + if (codec.codecType == webrtc::kVideoCodecMPEG4) + { + unsigned char configParameterSize = 0; + _vieCodec->GetCodecConfigParameters(_channelId, codec.codecSpecific.MPEG4.configParameters, configParameterSize); + codec.codecSpecific.MPEG4.configParametersSize = configParameterSize; + _vieCodec->SetReceiveCodec(_channelId, codec); + } + if (codec.codecType == webrtc::kVideoCodecI420) + { // Need to set the receive codec size + _vieCodec->SetReceiveCodec(_channelId, codec); + } +} + +void CDXChannelDlg::SetSendDestination() +{ + if(_externalTransport) + return; + + BYTE part1, part2, part3, part4; + char sendIP1[16]; + m_remoteIp1.GetAddress(part1, part2, part3, part4); + sprintf(sendIP1,"%d.%d.%d.%d",part1,part2,part3,part4); + + CString strPort; + m_remotePort1.GetWindowText(strPort); + int remotePort1 = _ttoi(strPort.GetString()); + +#ifdef IPV6 + char* recIP = "::0"; +#else + char* recIP = "0.0.0.0"; +#endif //IPV6 + + TEST_MUSTPASS(_vieNetwork->SetSendDestination(_channelId,sendIP1,remotePort1),kViENetworkAlreadySending); + + #ifndef NO_VOICE_ENGINE + m_localPort1.GetWindowText(strPort); + int localPort1 = _ttoi(strPort.GetString()); + int res=_veBase->SetLocalReceiver(_audioChannel,localPort1+2); + + TEST_MUSTPASS(_veBase->SetSendDestination(_audioChannel, remotePort1+2, sendIP1),-5) + #endif + +} + +void CDXChannelDlg::SetLocalReceiver() +{ + if(_externalTransport) + return; + + CString strPort; + m_localPort1.GetWindowText(strPort); + int localPort1 = _ttoi(strPort.GetString()); + + + + // May fail because we are sending + TEST_MUSTPASS(_vieNetwork->SetLocalReceiver(_channelId, localPort1),-5); + + #ifndef NO_VOICE_ENGINE + int res=_veBase->SetLocalReceiver(_audioChannel,localPort1+2); + #endif + + + +} + +void CDXChannelDlg::SetCaptureDevice() +{ + if(_parentChannel!=-1) // don't accept changing input on slave channels. + return; + + int camSel=-1; + camSel=m_ctrlDevice.GetCurSel(); + + CString captureStr; + //captureStr.Compare + m_ctrlDevice.GetLBText(camSel, captureStr); + if(captureStr!=_T("N/A") != 0) + { + + TEST_MUSTPASS(_vieFile->StopPlayFile(_captureId),kViEFileNotPlaying); + TEST_MUSTPASS(_vieCapture->DisconnectCaptureDevice(_channelId),kViECaptureDeviceNotConnected); + TEST_MUSTPASS(_vieRender->RemoveRenderer(_captureId),kViERenderInvalidRenderId); + + if(_captureId>=0x1001 && _captureId<0x10FF)// ID is a capture device + { + TEST_MUSTPASS(_captureDevicePool.ReturnCaptureDevice(_captureId),-5); + } + + if(captureStr!=_T("None")==0) + { + _captureId=-1; + } + else if(_tcsstr(captureStr,_T(".avi"))!=NULL ) // Selected an AVI file + { + TEST_MUSTPASS(_vieFile->StartPlayFile(TcharToChar(captureStr.GetBuffer(),-1),_captureId,false,webrtc::kFileFormatAviFile),-5); + TEST_MUSTPASS(_vieRender->AddRenderer(_captureId,m_ctrlLiveVideo.m_hWnd, 0, 0.0f, 0.0f,1.0f,1.0f),-5); + TEST_MUSTPASS(_vieRender->StartRender(_captureId),-5); + TEST_MUSTPASS(_vieFile->SendFileOnChannel(_captureId,_channelId),-5); + TEST_MUSTPASS(_vieFile->StartPlayFileAsMicrophone(_captureId,_channelId,true),-5); + //TEST_MUSTPASS(_vieFile->StartPlayAudioLocally(_captureId,_channelId),-5); + } + else + { + + char captureName[256]; + char uniqueCaptureName[256]; + + TEST_MUSTPASS(_vieCapture->GetCaptureDevice(camSel,captureName,256,uniqueCaptureName,256),-5); + + TEST_MUSTPASS(_captureDevicePool.GetCaptureDevice(_captureId,uniqueCaptureName),-5); + TEST_MUSTPASS(_vieCapture->StartCapture(_captureId),kViECaptureDeviceAlreadyStarted); + TEST_MUSTPASS(_vieCapture->RegisterObserver(_captureId,*this),kViECaptureObserverAlreadyRegistered); + + TEST_MUSTPASS(_vieRender->AddRenderer(_captureId,m_ctrlLiveVideo.m_hWnd, 0, 0.0f, 0.0f,1.0f,1.0f),-5); + TEST_MUSTPASS(_vieCapture->ConnectCaptureDevice(_captureId,_channelId),-5); + TEST_MUSTPASS(_vieRender->StartRender(_captureId),-5); + } + } + +} + + + +void CDXChannelDlg::OnBnClickedStartlisten() +{ + + + // Configure the local ports + SetLocalReceiver(); + + //Configure the remote destination- needed in order to be able to respond to RTCP messages + SetSendDestination(); + + + #ifndef NO_VOICE_ENGINE + TEST_MUSTPASS(_veBase->StartReceive(_audioChannel),-5); + #endif + TEST_MUSTPASS(_vieBase->StartReceive(_channelId),-5); + + +} + +void CDXChannelDlg::OnStartSend() +{ + + // Set the send destination + SetSendDestination(); + + // Configure the local ports (Needed to be able to receive RTCP + //SetLocalReceiver(); + + + // Set the send codec + SetSendCodec(); + + if(_captureId==-1) // If no capture device has been set. + SetCaptureDevice(); //Set the capture device + + + + //TEST_MUSTPASS(_vieRTPRTCP->SetStartSequenceNumber(_channelId,1),-5); + + // Start sending + TEST_MUSTPASS(_vieBase->StartSend(_channelId),-5); + + + #ifndef NO_VOICE_ENGINE + TEST_MUSTPASS(_veBase->StartSend(_audioChannel),-5); + #endif + + +} + +void CDXChannelDlg::ConfigureRender() +{ + TEST_MUSTPASS(_vieRender->AddRenderer(_channelId,m_ctrlLiveRemoteVideo.m_hWnd, 0, 0.0f, 0.0f,1.0f,1.0f),-5); + + TEST_MUSTPASS(_vieFile->SetRenderStartImage(_channelId,"renderStartImage.jpg"),-5); + TEST_MUSTPASS(_vieRender->StartRender(_channelId),-5); + TEST_MUSTPASS(_vieFile->SetRenderTimeoutImage(_channelId,"renderTimeoutImage.jpg"),-5); + + +} + + +void CDXChannelDlg::OnStopSend() +{ + + #ifndef NO_VOICE_ENGINE + TEST_MUSTPASS(_veBase->StopSend(_audioChannel),-5); + #endif + + + TEST_MUSTPASS(_vieBase->StopSend(_channelId),kViEBaseNotSending); // Accept error Not sending + + +} +void CDXChannelDlg::OnBnClickedStoplisten() +{ + + + #ifndef NO_VOICE_ENGINE + TEST_MUSTPASS(_veBase->StopReceive(_audioChannel),-5); + #endif + TEST_MUSTPASS(_vieBase->StopReceive(_channelId),-5); +} + + +void CDXChannelDlg::OnDestroy() +{ + + OnStopSend(); + OnBnClickedStoplisten(); + + if(_vieCapture && _parentChannel==-1) + { + _vieCapture->DisconnectCaptureDevice(_channelId); + _captureDevicePool.ReturnCaptureDevice(_captureId); + } + if(_vieFile && _parentChannel!=-1) + { + TEST_MUSTPASS(_vieFile->StopPlayFile(_captureId),kViEFileNotPlaying); + } + + + + + if(_videoEngine) + { + if(_parentChannel==-1) + { + _vieCodec->DeregisterEncoderObserver(_channelId); + } + _vieBase->DeleteChannel(_channelId); + _channelPool.RemoveChannel(_channelId); + } + + _videoEngine = NULL; +#ifndef NO_VOICE_ENGINE + + if (_voiceEngine) + { + _veBase->DeleteChannel(_audioChannel); + _veBase->Release(); + _veNetwork->Release(); + _veCodec->Release(); + _veRTCP->Release(); + } +#endif + + + strcpy(_logMsg,""); + SetEvent(_callbackEvent); + MSG msg; // Wait until the callback thread exits. Need to handle messages since the callback thread can call SendMessage when updating UI + while(WaitForSingleObject(_callbackThread,10)==WAIT_TIMEOUT) + { + DWORD ret = PeekMessage( &msg, NULL, 0, 0,PM_REMOVE ); + if (ret >0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + CloseHandle(_callbackThread); + CloseHandle(_callbackEvent); + DeleteCriticalSection(&_critCallback); + + TEST_MUSTPASS(_vieCapture->Release()<0,-5); + TEST_MUSTPASS(_vieRTPRTCP->Release()<0,-5); + TEST_MUSTPASS(_vieRender->Release()<0,-5); + TEST_MUSTPASS(_vieCodec->Release()<0,-5); + TEST_MUSTPASS(_vieNetwork->Release()<0,-5); + TEST_MUSTPASS(_vieFile->Release()<0,-5); + TEST_MUSTPASS(_vieBase->Release()<0,-5); + + + +#ifdef TEST_EXTERNAL_TRANSPORT + if(_transport) + delete _transport; + _transport = NULL; +#endif + + delete _externalTransport; + + CDialog::OnDestroy(); + if(_dialogObserver) + { + _dialogObserver->ChannelDialogEnded(this); + } +} + +void CDXChannelDlg::OnCancel() +{ + DestroyWindow(); +} +// If you add a minimize button to your dialog, you will need the code below +// to draw the icon. For MFC applications using the document/view model, +// this is automatically done for you by the framework. + +void CDXChannelDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +BOOL CDXChannelDlg::OnDeviceChange( UINT nID, DWORD lParam) +{ + if(nID == DBT_DEVNODES_CHANGED) + { + // SetCaptureDevice(); + } + return CDialog::OnDeviceChange(nID, lParam); +} + + +void CDXChannelDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if(SC_MAXIMIZE == nID) + {} + CDialog::OnSysCommand(nID, lParam); +} + + +static bool fullScreen = false; +void CDXChannelDlg::OnRButtonUp( UINT nFlags, CPoint point) +{ + CDialog::OnRButtonUp( nFlags, point); +} + +// The system calls this to obtain the cursor to display while the user drags +// the minimized window. +HCURSOR CDXChannelDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +void CDXChannelDlg::OnCbnSelchangeCodecList() +{ + SetSendCodec(); +} + + +void CDXChannelDlg::OnCbnSelchangeSize() +{ + SetSendCodec(); +} + +void CDXChannelDlg::OnCbnSelchangeDevice() +{ + + + SetCaptureDevice(); + +} + + +void CDXChannelDlg::OnCbnSelchangeBitrate() +{ + + SetSendCodec(); + +} + +void CDXChannelDlg::OnCbnSelchangeMinFrameRate() +{ + + SetSendCodec(); + +} + + +void CDXChannelDlg::OnBnClickedTmmbr() +{ + + TEST_MUSTPASS(_vieRTPRTCP->SetTMMBRStatus(_channelId,m_cbTmmbr.GetCheck()==BST_CHECKED),-5); + +} + +void CDXChannelDlg::OnCbnSelchangeRtcpmode() +{ + + /* + kRtcpNone = 0, + kRtcpCompound_RFC4585 = 1, + kRtcpNonCompound_RFC5506 = 2 */ + ViERTCPMode mode=ViERTCPMode(m_ctrlRtcpMode.GetCurSel()); + TEST_MUSTPASS(_vieRTPRTCP->SetRTCPStatus(_channelId,mode),-5); + +} + +void CDXChannelDlg::OnBnClickedFreezelog() +{ + _canAddLog=m_cbFreezeLog.GetCheck()!=BST_CHECKED; +} + +void CDXChannelDlg::OnBnClickedProtNack() +{ + + TEST_MUSTPASS(_vieRTPRTCP->SetNACKStatus(_channelId,true),-5); + +} + +void CDXChannelDlg::OnBnClickedProtNone() +{ + + TEST_MUSTPASS(_vieRTPRTCP->SetNACKStatus(_channelId,false),-5); + TEST_MUSTPASS(_vieRTPRTCP->SetFECStatus(_channelId,false,0,0),-5); +} + +void CDXChannelDlg::OnBnClickedProtFec() +{ + int noCodec=_vieCodec->NumberOfCodecs(); + int redPayloadType=0; + int fecPayloadType=0; + for(unsigned char i=0;iGetCodec(i,codec); + if(codec.codecType==webrtc::kVideoCodecRED) + { + redPayloadType=codec.plType; + } + if(codec.codecType==webrtc::kVideoCodecULPFEC) + { + fecPayloadType=codec.plType; + } + } + TEST_MUSTPASS(_vieRTPRTCP->SetFECStatus(_channelId,true,redPayloadType,fecPayloadType),-5); +} + +void CDXChannelDlg::OnBnClickedCameracap() +{ + char version[1024]; + _vieBase->GetVersion(version); + MessageBox(CharToTchar(version,-1)); + int p=strlen(version); +#ifndef NO_VOICE_ENGINE + _veBase->GetVersion(version); + MessageBox(CharToTchar(version,-1)); +#endif +} + +unsigned int WINAPI CDXChannelDlg::CallbackThread(LPVOID lpParameter) +{ + static_cast(lpParameter)->CallbackThreadProcess(); + return 0; +} + +void CDXChannelDlg::CallbackThreadProcess() +{ + while(1) + { + if(WAIT_OBJECT_0==WaitForSingleObject(_callbackEvent,INFINITE)) + { + char smsg[512]; + EnterCriticalSection(&_critCallback); + strncpy(smsg,_logMsg,strlen(_logMsg)+1); + strcpy(_logMsg,""); + + + LeaveCriticalSection(&_critCallback); + if(strstr(smsg,"Send")!=NULL) + { + unsigned short fractionLost=0; + unsigned int cumulativeLost=0; + unsigned int extendedMax=0; + unsigned int jitter=0; + int rttMs=0; + + + + _vieRTPRTCP->GetReceivedRTCPStatistics(_channelId, + fractionLost, + cumulativeLost, + extendedMax, + jitter, + rttMs); + + //int bw=0; + //if(_vieCodec->GetAvailableBandwidth(_channelId,bw)==0) + //{ + // sprintf(smsg,"%s, rtt %d, loss %d,bw %d", smsg,rttMs,fractionLost,bw); + //} + //else + //{ + // _vieBase->LastError(); // Reset last error. + //} + + + + } + if(strlen(smsg)) + { + m_ctrlInfo.InsertString(0,(LPCTSTR) CharToTchar(smsg,-1)); + while(m_ctrlInfo.GetCount()==151) + m_ctrlInfo.DeleteString(150); + } + else + { + break; // End the callback thread + } + } + } + +} +void CDXChannelDlg::AddToInfo(const char* msg) +{ + if(!_canAddLog) + return; + EnterCriticalSection(&_critCallback); + + SYSTEMTIME systemTime; + GetSystemTime(&systemTime); + + if(strlen(_logMsg)==0) + { + SetEvent(_callbackEvent); // Notify of new + } + + sprintf (_logMsg, "(%2u:%2u:%2u:%3u) %s", systemTime.wHour, + systemTime.wMinute, + systemTime.wSecond, + systemTime.wMilliseconds, + msg + ); + + + + LeaveCriticalSection(&_critCallback); + + +} + +void CDXChannelDlg::IncomingRate(const int videoChannel, + unsigned int framerate, + unsigned int bitrate) +{ + char str[64]; + sprintf(str,"Incoming Fr:%d br %d\n", framerate, bitrate); + AddToInfo(str); +} + +void CDXChannelDlg::RequestNewKeyFrame(int channel) +{ + assert(!"(RequestNewKeyFrame why is it called"); +} +void CDXChannelDlg::PerformanceAlarm(unsigned int cpuLoad) +{ + char str[64]; + sprintf(str,"Performance alarm %d",cpuLoad); + AddToInfo(str); +} +void CDXChannelDlg::OutgoingRate(const int videoChannel, + unsigned int framerate, + unsigned int bitrate) + { + char str[64]; + sprintf(str,"Send Fr:%d br %d", framerate, bitrate); + AddToInfo(str); + } +void CDXChannelDlg::IncomingCodecChanged(const int videoChannel, + const VideoCodec& videoCodec) + { + char str[128]; + sprintf(str,"Incoming codec channel:%d pltype:%d width:%d height:%d\n", videoChannel, videoCodec.plType, videoCodec.width,videoCodec.height); + AddToInfo(str); + } +void CDXChannelDlg::BrightnessAlarm(const int captureId, + const Brightness brightness) +{ + + switch(brightness) + { + case Normal: + AddToInfo("BrightnessAlarm - image ok.\n"); + break; + case Bright: + AddToInfo("BrightnessAlarm - light image.\n"); + break; + case Dark: + AddToInfo("BrightnessAlarm - dark image.\n"); + break; + } +} + +void CDXChannelDlg::CapturedFrameRate(const int captureId, + const unsigned char frameRate) +{ + char str[64]; + sprintf(str,"Local Camera Frame rate:%d \n", frameRate); + AddToInfo(str); +} + +void CDXChannelDlg::NoPictureAlarm(const int captureId, + const CaptureAlarm alarm) +{ + char str[64]; + sprintf(str,"No Picture alarm\n"); + AddToInfo(str); + +} + + +void CDXChannelDlg::OnBnClickedExttransport() +{ + if(m_cbExternalTransport.GetCheck()==BST_CHECKED) + { + m_localPort1.EnableWindow(FALSE); + m_remotePort1.EnableWindow(FALSE); + m_remoteIp1.EnableWindow(FALSE); + m_ctrlPacketLoss.EnableWindow(TRUE); + m_ctrlDelay.EnableWindow(TRUE); + _externalTransport= new tbExternalTransport(*_vieNetwork); + _vieNetwork->RegisterSendTransport(_channelId,*_externalTransport); + } + else + { + _vieNetwork->DeregisterSendTransport(_channelId); + + delete _externalTransport; + _externalTransport=NULL; + m_localPort1.EnableWindow(TRUE); + m_remotePort1.EnableWindow(TRUE); + m_remoteIp1.EnableWindow(TRUE); + m_ctrlPacketLoss.EnableWindow(FALSE); + m_ctrlDelay.EnableWindow(FALSE); + } +} + + +void CDXChannelDlg::OnCbnSelchangePacketloss() +{ + if(_externalTransport) + { + _externalTransport->SetPacketLoss(m_ctrlPacketLoss.GetCurSel()*2); + } +} + + +void CDXChannelDlg::OnCbnSelchangeDelay() +{ + if(_externalTransport) + { + _externalTransport->SetNetworkDelay(m_ctrlDelay.GetCurSel()*30); + } + +} + +void CDXChannelDlg::OnBnClickedBtnRecordIncoming() +{ + + CButton *recordBtn = (CButton *) GetDlgItem(IDC_BTN_RECORD_INCOMING); + + CString text; + recordBtn->GetWindowText(text); + if(text!=_T("Stop Rec Inc")!=0) + { + recordBtn->SetWindowText(_T("Stop Rec Inc")); + SYSTEMTIME time; + GetSystemTime(&time); + sprintf(_fileName,"IncomingChannel%d_%4d%2d%2d%2d%2d.avi",_channelId,time.wYear,time.wMonth,time.wDay,time.wHour,time.wMinute); + + AudioSource audioSource=PLAYOUT; + webrtc::CodecInst audioCodec; + strcpy(audioCodec.plname,"L16"); + audioCodec.rate = 256000; + audioCodec.plfreq = 16000; + audioCodec.pacsize = 160; + + webrtc::VideoCodec videoCodec; + memset(&videoCodec,0,sizeof(videoCodec)); + + strcpy(videoCodec.plName,"VP8"); + videoCodec.maxBitrate=1000; + videoCodec.startBitrate=1000; + videoCodec.width=352; + videoCodec.height=288; + videoCodec.codecType=webrtc::kVideoCodecVP8; + videoCodec.maxFramerate=30; + TEST_MUSTPASS(_vieFile->StartRecordIncomingVideo(_channelId,_fileName,audioSource,audioCodec, videoCodec),-5); + } + else + { + recordBtn->SetWindowText(_T("Record Incoming")); + TEST_MUSTPASS(_vieFile->StopRecordIncomingVideo(_channelId),-5); + CString msg; + msg.AppendFormat(_T("Recorded file %s"),_fileName); + MessageBox(msg); + } +} + +void CDXChannelDlg::OnBnClickedBtnRecordOutgoing() +{ + + CButton *recordBtn = (CButton *) GetDlgItem(IDC_BTN_RECORD_OUTGOING); + CString text; + recordBtn->GetWindowText(text); + if(text!=_T("Stop Rec Out")) + { + recordBtn->SetWindowText(_T("Stop Rec Out")); + SYSTEMTIME time; + GetSystemTime(&time); + sprintf(_fileName,"OutgoingChannel%d_%4d%2d%2d%2d%2d.avi",_channelId,time.wYear,time.wMonth,time.wDay,time.wHour,time.wMinute); + + AudioSource audioSource=MICROPHONE; + webrtc::CodecInst audioCodec; + strcpy(audioCodec.plname,"L16"); + audioCodec.rate = 256000; + audioCodec.plfreq = 16000; + audioCodec.pacsize = 160; + + webrtc::VideoCodec videoCodec; + memset(&videoCodec,0,sizeof(videoCodec)); + + strcpy(videoCodec.plName,"VP8"); + videoCodec.maxBitrate=1000; + videoCodec.startBitrate=1000; + videoCodec.width=352; + videoCodec.height=288; + videoCodec.codecType=webrtc::kVideoCodecVP8; + videoCodec.maxFramerate=30; + TEST_MUSTPASS(_vieFile->StartRecordOutgoingVideo(_channelId,_fileName,audioSource,audioCodec,videoCodec),-5); + } + else + { + recordBtn->SetWindowText(_T("Record Outgoing")); + TEST_MUSTPASS(_vieFile->StopRecordOutgoingVideo(_channelId),-5); + CString msg; + msg.AppendFormat(_T("Recorded file %s"),_fileName); + MessageBox(msg); + } +} + +void CDXChannelDlg::OnBnClickedBtnCreateSlave() +{ + CDXChannelDlg* newSlave =new CDXChannelDlg(_videoEngine,_captureDevicePool,_channelPool,_voiceEngine,NULL,_dialogObserver,_channelId); + newSlave->Create(CDXChannelDlg::IDD,NULL); +} diff --git a/video_engine/main/test/WindowsTest/ChannelDlg.h b/video_engine/main/test/WindowsTest/ChannelDlg.h new file mode 100644 index 0000000000..59b8d073e4 --- /dev/null +++ b/video_engine/main/test/WindowsTest/ChannelDlg.h @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_CHANNELDLG_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_CHANNELDLG_H_ + +#include "StdAfx.h" +//#define NO_VOICE_ENGINE + +///////////////////////////////////////////////////////////////////////////// +// CDXChannelDlg dialog +// Include ViE headers + +#include "common_types.h" + +#include "vie_base.h" +#include "vie_capture.h" +#include "vie_codec.h" +#include "vie_network.h" +#include "vie_render.h" +#include "vie_rtp_rtcp.h" +#include "vie_errors.h" +#include "vie_file.h" +#include "tbExternalTransport.h" + +#include "resource.h" // main symbols + + +#ifndef NO_VOICE_ENGINE + +#include "voe_base.h" +#include "voe_errors.h" +#include "voe_base.h" +#include "voe_network.h" +#include "voe_codec.h" +#include "voe_rtp_rtcp.h" +#endif + +using namespace webrtc; +class CDXChannelDlg; +class CaptureDevicePool; +class ChannelPool; + +#define TEST_MUSTPASS(expr,oklasterror) \ + { \ + if ((expr)) \ + { \ + CString r_msg; \ + int r_lastError=_vieBase->LastError(); \ + CString exp; \ + exp=#expr;\ + r_msg.Format(_T("\nError at line:%i, %s \nError code: %i\n"),__LINE__, exp,r_lastError); \ + if(r_lastError!=oklasterror) \ + ::MessageBox (NULL, (LPCTSTR)r_msg, TEXT("Error Message"), MB_OK | MB_ICONINFORMATION); \ + } \ + } + +class CDXChannelDlgObserver +{ +public: + virtual void ChannelDialogEnded(CDXChannelDlg* context)=0; + +protected: + virtual ~CDXChannelDlgObserver(){}; + +}; + +class CDXChannelDlg : public CDialog , public ViEEncoderObserver, public ViEDecoderObserver, public ViEBaseObserver, public ViECaptureObserver +{ +// Construction +public: + CDXChannelDlg(VideoEngine* videoEngine, + CaptureDevicePool& captureDevicePool, + ChannelPool& channelPool, + void* voiceEngine=NULL + ,CWnd* pParent = NULL,CDXChannelDlgObserver* observer=NULL,int parentChannel=-1); // standard constructor + +// Dialog Data + //{{AFX_DATA(CDXChannelDlg) + enum { IDD = IDD_DXQUALITY_DIALOG }; + CComboBox m_ctrlDevice; + CComboBox m_ctrlCodec; + CComboBox m_ctrlBitrate; + CComboBox m_ctrlCodecSize; + CComboBox m_ctrlRtcpMode; + CComboBox m_ctrlPacketBurst; + CComboBox m_ctrlMinFrameRate; + + CListBox m_ctrlInfo; + + CStatic m_ctrlLiveRemoteVideo; + CStatic m_ctrlLiveVideo; + CEdit m_localPort1; + CEdit m_remotePort1; + CIPAddressCtrl m_remoteIp1; + CButton m_cbTmmbr; + CButton m_cbExternalTransport; + CButton m_cbFreezeLog; + CButton m_cbDefaultSendChannel; + CComboBox m_ctrlPacketLoss; + CComboBox m_ctrlDelay; + + + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CDXChannelDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + + + +public : + // Callback + + //Capture observer + virtual void BrightnessAlarm(const int captureId, + const Brightness brightness); + + virtual void CapturedFrameRate(const int captureId, + const unsigned char frameRate); + + virtual void NoPictureAlarm(const int captureId, + const CaptureAlarm alarm); + + + // same callback method is being used to raise also to clear. + // true - raise, false - clear + // virtual void NoPictureAlarm(bool active = true); + + // Encoder observer + virtual void OutgoingRate(const int videoChannel, + const unsigned int framerate, + const unsigned int bitrate) ; + + //Decoder observer + virtual void IncomingCodecChanged(const int videoChannel, + const VideoCodec& videoCodec); + + virtual void IncomingRate(const int videoChannel, + const unsigned int framerate, + const unsigned int bitrate); + + virtual void RequestNewKeyFrame(const int videoChannel); + + // Base observer + virtual void PerformanceAlarm(const unsigned int cpuLoad); + + + //virtual void IncomingCSRCChanged(int channel, unsigned int csrc, bool added); + + + +// Implementation +protected: + HICON m_hIcon; + int _channelId; + int _parentChannel; + int _audioChannel; + bool _canAddLog; + + // Thread and function for callbacks + CRITICAL_SECTION _critCallback; + HANDLE _callbackThread; + HANDLE _callbackEvent; + char _logMsg[512]; + static unsigned int WINAPI CallbackThread(LPVOID lpParameter); + void CallbackThreadProcess(); + + + + //void GetSize(int sizeSel, int &width, int &height); + virtual void ConfigureRender(); + + virtual void SetCaptureDevice(); + virtual void SetLocalReceiver(); + virtual void SetSendDestination(); + virtual void SetSendCodec(); + + + void AddToInfo(const char* msg); + + // afx_msg void Command(UINT nID, LPARAM lParam); + + // Generated message map functions + //{{AFX_MSG(CDXChannelDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnRButtonUp( UINT nFlags, CPoint point); + afx_msg BOOL OnDeviceChange( UINT, DWORD ); + afx_msg void OnPaint(); + //afx_msg LRESULT OnDisplayChange(WPARAM, LPARAM); + afx_msg HCURSOR OnQueryDragIcon(); + virtual afx_msg void OnStartSend(); + virtual afx_msg void OnDestroy(); + virtual afx_msg void OnStopSend(); + virtual afx_msg void OnCancel(); + afx_msg void OnTimer(UINT nIDEvent); + + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +private: + CDXChannelDlgObserver* _dialogObserver; + + VideoEngine* _videoEngine; + ViEBase* _vieBase; + ViECapture* _vieCapture; + ViERTP_RTCP* _vieRTPRTCP; + ViERender* _vieRender; + ViECodec* _vieCodec; + ViENetwork* _vieNetwork; + ViEFile* _vieFile; + tbExternalTransport* _externalTransport; + char _fileName[256]; + + +#ifndef NO_VOICE_ENGINE + VoiceEngine* _voiceEngine; + VoEBase* _veBase; + VoENetwork* _veNetwork; + VoECodec* _veCodec; + VoERTP_RTCP* _veRTCP; +#else + void* _voiceEngine; + +#endif + + VideoCodec _sendCodec; + int _captureId; + CaptureDevicePool& _captureDevicePool; + ChannelPool& _channelPool; + + + afx_msg void OnCbnSelchangeCodecList(); + afx_msg void OnCbnSelchangeDevice(); + afx_msg void OnCbnSelchangeSize(); + afx_msg void OnCbnSelchangeBitrate(); + afx_msg void OnCbnSelchangeWindowSize(); + afx_msg void OnBnClickedversion(); + afx_msg void OnCbnSelchangeMinFrameRate(); + afx_msg void OnBnClickedStartlisten(); + afx_msg void OnBnClickedStoplisten(); + afx_msg void OnBnClickedStopsend(); + afx_msg void OnBnClickedTmmbr(); + afx_msg void OnCbnSelchangeRtcpmode(); + afx_msg void OnBnClickedProtNack(); + afx_msg void OnBnClickedProtNone(); + afx_msg void OnBnClickedProtFec(); + afx_msg void OnBnClickedFreezelog(); + afx_msg void OnBnClickedCameracap(); +public: + afx_msg void OnBnClickedExttransport(); + afx_msg void OnCbnSelchangePacketloss(); + afx_msg void OnCbnSelchangeDelay(); + afx_msg void OnBnClickedBtnRecordIncoming(); + afx_msg void OnBnClickedBtnRecordOutgoing(); + afx_msg void OnBnClickedBtnCreateSlave(); +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_CHANNELDLG_H_ diff --git a/video_engine/main/test/WindowsTest/ChannelPool.cpp b/video_engine/main/test/WindowsTest/ChannelPool.cpp new file mode 100644 index 0000000000..dbd1644fae --- /dev/null +++ b/video_engine/main/test/WindowsTest/ChannelPool.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "ChannelPool.h" +#include "map_wrapper.h" +#include +#include +#include "critical_section_wrapper.h" + +ChannelPool::ChannelPool(): +_critSect(*webrtc::CriticalSectionWrapper::CreateCriticalSection()) +{ +} + +ChannelPool::~ChannelPool(void) +{ + assert(_channelMap.Size()==0); + delete &_critSect; +} + +WebRtc_Word32 ChannelPool::AddChannel(int channel) +{ + return _channelMap.Insert(channel,(void*) channel); +} +WebRtc_Word32 ChannelPool::RemoveChannel(int channel) +{ + return _channelMap.Erase(channel); +} + +webrtc::MapWrapper& ChannelPool::ChannelMap() +{ + return _channelMap; +} diff --git a/video_engine/main/test/WindowsTest/ChannelPool.h b/video_engine/main/test/WindowsTest/ChannelPool.h new file mode 100644 index 0000000000..374c676a31 --- /dev/null +++ b/video_engine/main/test/WindowsTest/ChannelPool.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#pragma once +#include "StdAfx.h" +#include "common_types.h" + +#include "vie_base.h" +#include "map_wrapper.h" + +namespace webrtc { +class CriticalSectionWrapper; +} + +class ChannelPool +{ +public: + ChannelPool(); + ~ChannelPool(void); + WebRtc_Word32 AddChannel(int channel); + WebRtc_Word32 RemoveChannel(int channel); + + webrtc::MapWrapper& ChannelMap(); + + private: + webrtc::CriticalSectionWrapper& _critSect; + webrtc::MapWrapper _channelMap; + +}; diff --git a/video_engine/main/test/WindowsTest/StdAfx.h b/video_engine/main/test/WindowsTest/StdAfx.h new file mode 100644 index 0000000000..78b1fbddfd --- /dev/null +++ b/video_engine/main/test/WindowsTest/StdAfx.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_STDAFX_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_STDAFX_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_STDAFX_H_ diff --git a/video_engine/main/test/WindowsTest/VideoSize.h b/video_engine/main/test/WindowsTest/VideoSize.h new file mode 100644 index 0000000000..60e2bdd070 --- /dev/null +++ b/video_engine/main/test/WindowsTest/VideoSize.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_VIDEOSIZE_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_VIDEOSIZE_H_ +#include "StdAfx.h" +enum VideoSize + { + UNDEFINED, + SQCIF, // 128*96 = 12 288 + QQVGA, // 160*120 = 19 200 + QCIF, // 176*144 = 25 344 + CGA, // 320*200 = 64 000 + QVGA, // 320*240 = 76 800 + SIF, // 352*240 = 84 480 + WQVGA, // 400*240 = 96 000 + CIF, // 352*288 = 101 376 + W288P, // 512*288 = 147 456 (WCIF) + W368P, // 640*368 = 235 520 + S_448P, // 576*448 = 281 088 + VGA, // 640*480 = 307 200 + S_432P, // 720*432 = 311 040 + W432P, // 768*432 = 331 776 (a.k.a WVGA 16:9) + S_4SIF, // 704*480 = 337 920 + W448P, // 768*448 = 344 064 + NTSC, // 720*480 = 345 600 + FW448P, // 800*448 = 358 400 + S_768x480P, // 768*480 = 368 640 (a.k.a WVGA 16:10) + WVGA, // 800*480 = 384 000 + S_4CIF, // 704576 = 405 504 + SVGA, // 800*600 = 480 000 + W544P, // 960*544 = 522 240 + W576P, // 1024*576 = 589 824 (W4CIF) + HD, // 960*720 = 691 200 + XGA, // 1024*768 = 786 432 + WHD, // 1280*720 = 921 600 + FULL_HD, // 1440*1080 = 1 555 200 + UXGA, // 1600*1200 = 1 920 000 + WFULL_HD, // 1920*1080 = 2 073 600 + NUMBER_OF_VIDEO_SIZE + }; + +int GetWidthHeight(VideoSize size, int& width, int& height); + + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_VIDEOSIZE_H_ diff --git a/video_engine/main/test/WindowsTest/WindowsTest.cpp b/video_engine/main/test/WindowsTest/WindowsTest.cpp new file mode 100644 index 0000000000..ceda8a99da --- /dev/null +++ b/video_engine/main/test/WindowsTest/WindowsTest.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "WindowsTest.h" +#include "ChannelDlg.h" +#include "WindowsTestMainDlg.h" +#include "engine_configurations.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +// Check memory leaks id running debug +#if (defined(_DEBUG) && defined(_WIN32)) +// #include "vld.h" +#endif +///////////////////////////////////////////////////////////////////////////// +// CDXWindowsTestApp + +BEGIN_MESSAGE_MAP(CDXWindowsTestApp, CWinApp) + //{{AFX_MSG_MAP(CDXWindowsTestApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CDXWindowsTestApp construction + +CDXWindowsTestApp::CDXWindowsTestApp() +{ + +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only object + +CDXWindowsTestApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CDXWindowsTestApp initialization + +BOOL CDXWindowsTestApp::InitInstance() +{ + int result=0; + #ifndef NO_VOICE_ENGINE + _voiceEngine = VoiceEngine::Create(); + _veBase = VoEBase::GetInterface(_voiceEngine); + result+=_veBase->Init(); + #else + _voiceEngine=NULL; + #endif + + _videoEngine = VideoEngine::Create(); + + _videoEngine->SetTraceFilter(webrtc::kTraceDefault);//webrtc::kTraceDebug | webrtc::kTraceError | webrtc::kTraceApiCall | webrtc::kTraceWarning | webrtc::kTraceCritical | webrtc::kTraceStateInfo | webrtc::kTraceInfo | webrtc::kTraceStream); + _videoEngine->SetTraceFile("trace.txt"); + + ViEBase* vieBase=ViEBase::GetInterface(_videoEngine); + result+=vieBase->Init(); + if(result!=0) + { + ::MessageBox (NULL, (LPCTSTR)("failed to init VideoEngine"), TEXT("Error Message"), MB_OK | MB_ICONINFORMATION); + } + + { + WindowsTestMainDlg dlg(_videoEngine,_voiceEngine); + + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + } + + vieBase->Release(); + + if(!VideoEngine::Delete(_videoEngine)) + { + char errorMsg[255]; + sprintf(errorMsg,"All VideoEngine interfaces are not released properly!"); + ::MessageBox (NULL, (LPCTSTR)errorMsg, TEXT("Error Message"), MB_OK | MB_ICONINFORMATION); + } + + #ifndef NO_VOICE_ENGINE + + _veBase->Terminate(); + if(_veBase->Release()!=0) + { + // ensure that no interface is still referenced + char errorMsg[256]; + sprintf(errorMsg,"All VoiceEngine interfaces are not released properly!"); + ::MessageBox (NULL, (LPCTSTR)errorMsg, TEXT("Error Message"), MB_OK | MB_ICONINFORMATION); + } + + if (false == VoiceEngine::Delete(_voiceEngine)) + { + char errorMsg[256]; + sprintf(errorMsg,"VoiceEngine::Delete() failed!"); + ::MessageBox (NULL, (LPCTSTR)errorMsg, TEXT("Error Message"), MB_OK | MB_ICONINFORMATION); + } + #endif + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/video_engine/main/test/WindowsTest/WindowsTest.h b/video_engine/main/test/WindowsTest/WindowsTest.h new file mode 100644 index 0000000000..dc3ee9d26b --- /dev/null +++ b/video_engine/main/test/WindowsTest/WindowsTest.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_WINDOWSTEST_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_WINDOWSTEST_H_ + + +#include "StdAfx.h" +#include "resource.h" // main symbols + + + +///////////////////////////////////////////////////////////////////////////// + +//Forward declarations +namespace webrtc { + class VoiceEngine; + class VoEBase; + class VideoEngine; +} +using namespace webrtc; + +class CDXWindowsTestApp : public CWinApp +{ +public: + CDXWindowsTestApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CDXWindowsTestApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CDXWindowsTestApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + VideoEngine* _videoEngine; + VoiceEngine* _voiceEngine; + VoEBase* _veBase; +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_WINDOWSTEST_H_ diff --git a/video_engine/main/test/WindowsTest/WindowsTestMainDlg.cpp b/video_engine/main/test/WindowsTest/WindowsTestMainDlg.cpp new file mode 100644 index 0000000000..fcc490d93b --- /dev/null +++ b/video_engine/main/test/WindowsTest/WindowsTestMainDlg.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// WindowsTestMainDlg.cpp : implementation file +// +#include "WindowsTestMainDlg.h" +#include "WindowsTest.h" +#include "ChannelDlg.h" + +#include "voe_base.h" + +// WindowsTestMainDlg dialog + +IMPLEMENT_DYNAMIC(WindowsTestMainDlg, CDialog) + +WindowsTestMainDlg::WindowsTestMainDlg(VideoEngine* videoEngine,void* voiceEngine,CWnd* pParent /*=NULL*/) + : CDialog(WindowsTestMainDlg::IDD, pParent), + _videoEngine(videoEngine), + _voiceEngine((VoiceEngine*) voiceEngine), + _testDlg1(NULL), + _testDlg2(NULL), + _testDlg3(NULL), + _testDlg4(NULL), + _externalInWidth(0), + _externalInHeight(0), + _externalInVideoType(0), + _captureDevicePool(videoEngine) +{ + +} + +WindowsTestMainDlg::~WindowsTestMainDlg() +{ +} + +void WindowsTestMainDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + + +BEGIN_MESSAGE_MAP(WindowsTestMainDlg, CDialog) + ON_BN_CLICKED(IDC_CHANNEL1, &WindowsTestMainDlg::OnBnClickedChannel1) + ON_BN_CLICKED(IDC_CHANNEL2, &WindowsTestMainDlg::OnBnClickedChannel2) + ON_BN_CLICKED(IDC_CHANNEL3, &WindowsTestMainDlg::OnBnClickedChannel3) + ON_BN_CLICKED(IDC_CHANNEL4, &WindowsTestMainDlg::OnBnClickedChannel4) +END_MESSAGE_MAP() + + + +void WindowsTestMainDlg::OnBnClickedChannel1() +{ + if(!_testDlg1) + { + _testDlg1=new CDXChannelDlg(_videoEngine,_captureDevicePool,_channelPool,_voiceEngine,NULL,this); + _testDlg1->Create(CDXChannelDlg::IDD,this); + } + else + { + _testDlg1->SetActiveWindow(); + } +} + +void WindowsTestMainDlg::OnBnClickedChannel2() +{ + if(!_testDlg2) + { + _testDlg2=new CDXChannelDlg(_videoEngine,_captureDevicePool,_channelPool,_voiceEngine,NULL,this); + _testDlg2->Create(CDXChannelDlg::IDD,this); + + } + else + { + _testDlg2->SetActiveWindow(); + } +} + +void WindowsTestMainDlg::ChannelDialogEnded(CDXChannelDlg* context) +{ + if(context==_testDlg4) + { + delete _testDlg4; + _testDlg4=NULL; + } + else if(context==_testDlg3) + { + delete _testDlg3; + _testDlg3=NULL; + } + else if(context==_testDlg2) + { + delete _testDlg2; + _testDlg2=NULL; + } + else if(context==_testDlg1) + { + delete _testDlg1; + _testDlg1=NULL; + } + else // Slave channel + { + delete context; + } + +} + + + +void WindowsTestMainDlg::OnBnClickedChannel3() +{ + if(!_testDlg3) + { + _testDlg3=new CDXChannelDlg(_videoEngine,_captureDevicePool,_channelPool,_voiceEngine,NULL,this); + _testDlg3->Create(CDXChannelDlg::IDD,this); + + } + else + { + _testDlg3->SetActiveWindow(); + } +} + +void WindowsTestMainDlg::OnBnClickedChannel4() +{ + if(!_testDlg4) + { + _testDlg4=new CDXChannelDlg(_videoEngine,_captureDevicePool,_channelPool,_voiceEngine,NULL,this); + _testDlg4->Create(CDXChannelDlg::IDD,this); + + } + else + { + _testDlg4->SetActiveWindow(); + } +} diff --git a/video_engine/main/test/WindowsTest/WindowsTestMainDlg.h b/video_engine/main/test/WindowsTest/WindowsTestMainDlg.h new file mode 100644 index 0000000000..8aae99a9e1 --- /dev/null +++ b/video_engine/main/test/WindowsTest/WindowsTestMainDlg.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#pragma once +#include "StdAfx.h" +#include "WindowsTestResource.h" + +#include "ChannelDlg.h" +#include "CaptureDevicePool.h" +#include "ChannelPool.h" + +//Forward declarations +namespace webrtc { + class VideoEngine; + class VoiceEngine; +} +using namespace webrtc; +class CDXCaptureDlg; + + +class WindowsTestMainDlg : public CDialog, private CDXChannelDlgObserver +{ + DECLARE_DYNAMIC(WindowsTestMainDlg) + +public: + WindowsTestMainDlg(VideoEngine* videoEngine,void* voiceEngine=NULL,CWnd* pParent = NULL); // standard constructor + virtual ~WindowsTestMainDlg(); + +// Dialog Data + enum { IDD = IDD_WINDOWSTEST_MAIN }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedChannel1(); + afx_msg void OnBnClickedChannel2(); + afx_msg void OnBnClickedChannel3(); + afx_msg void OnBnClickedChannel4(); + + + VideoEngine* _videoEngine; + VoiceEngine* _voiceEngine; + VoEBase* _veBase; + + CDXChannelDlg* _testDlg1; + CDXChannelDlg* _testDlg2; + CDXChannelDlg* _testDlg3; + CDXChannelDlg* _testDlg4; + + int _externalInWidth; + int _externalInHeight; + int _externalInVideoType; + + CaptureDevicePool _captureDevicePool; + ChannelPool _channelPool; + + +private: + virtual void ChannelDialogEnded(CDXChannelDlg* context); + +public: + +}; diff --git a/video_engine/main/test/WindowsTest/WindowsTestResouce.rc b/video_engine/main/test/WindowsTest/WindowsTestResouce.rc new file mode 100644 index 0000000000..5e866ad614 --- /dev/null +++ b/video_engine/main/test/WindowsTest/WindowsTestResouce.rc @@ -0,0 +1,101 @@ +// Microsoft Visual C++ generated resource script. +// +#include "WindowsTestResource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Swedish resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_SVE) +#ifdef _WIN32 +LANGUAGE LANG_SWEDISH, SUBLANG_DEFAULT +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "WindowsTestResource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_WINDOWSTEST_MAIN DIALOGEX 0, 0, 186, 156 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Windows ViE Test" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + PUSHBUTTON "Channel 1",IDC_CHANNEL1,129,45,50,14 + PUSHBUTTON "Channel 2",IDC_CHANNEL2,129,62,50,14 + PUSHBUTTON "Channel 3",IDC_CHANNEL3,129,79,50,14 + PUSHBUTTON "Channel 4",IDC_CHANNEL4,129,96,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_WINDOWSTEST_MAIN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 149 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Swedish resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/video_engine/main/test/WindowsTest/WindowsTestResource.h b/video_engine/main/test/WindowsTest/WindowsTestResource.h new file mode 100644 index 0000000000..2d49c28a6f --- /dev/null +++ b/video_engine/main/test/WindowsTest/WindowsTestResource.h @@ -0,0 +1,28 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by WindowsTestResouce.rc +// +#define IDD_WINDOWSTEST_MAIN 101 +#define IDC_CHANNEL1 1001 +#define IDC_CHANNEL2 1002 +#define IDC_CHANNEL3 1004 +#define IDC_CHANNEL4 1005 +#define IDC_POSITION 1009 +#define IDC_INFORMATION 1050 +#define IDC_CHECK_CHANNEL1 1070 +#define IDC_CHECK_CHANNEL2 1071 +#define IDC_CHECK_CHANNEL3 1072 +#define IDC_CHECK_CHANNEL4 1073 +#define IDC_COMBO1 1074 +#define IDC_BTN_CREATE2 1076 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 106 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1076 +#define _APS_NEXT_SYMED_VALUE 107 +#endif +#endif diff --git a/video_engine/main/test/WindowsTest/captureDeviceImage.jpg b/video_engine/main/test/WindowsTest/captureDeviceImage.jpg new file mode 100644 index 0000000000..3bb3ba48bb Binary files /dev/null and b/video_engine/main/test/WindowsTest/captureDeviceImage.jpg differ diff --git a/video_engine/main/test/WindowsTest/renderStartImage.jpg b/video_engine/main/test/WindowsTest/renderStartImage.jpg new file mode 100644 index 0000000000..b10a84259c Binary files /dev/null and b/video_engine/main/test/WindowsTest/renderStartImage.jpg differ diff --git a/video_engine/main/test/WindowsTest/renderTimeoutImage.jpg b/video_engine/main/test/WindowsTest/renderTimeoutImage.jpg new file mode 100644 index 0000000000..cb34d67664 Binary files /dev/null and b/video_engine/main/test/WindowsTest/renderTimeoutImage.jpg differ diff --git a/video_engine/main/test/WindowsTest/res/Capture.rc2 b/video_engine/main/test/WindowsTest/res/Capture.rc2 new file mode 100644 index 0000000000..d9acfd2f5f --- /dev/null +++ b/video_engine/main/test/WindowsTest/res/Capture.rc2 @@ -0,0 +1,13 @@ +// +// DXCAPTURE.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/video_engine/main/test/WindowsTest/resource.h b/video_engine/main/test/WindowsTest/resource.h new file mode 100644 index 0000000000..deb7944c40 --- /dev/null +++ b/video_engine/main/test/WindowsTest/resource.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Capture.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_DXQUALITY_DIALOG 102 +#define IDI_ICON1 130 +#define IDD_SLAVE_CHANNEL 132 +#define IDC_LIVEVIDEO 1000 +#define IDC_CAPTURE 1001 +#define IDC_DEVICE 1003 +#define IDC_STARTSEND 1004 +#define IDC_STARTLISTEN 1006 +#define IDC_STOPLISTEN 1007 +#define IDC_STOPSend 1008 +#define IDC_CODEC_LIST 1010 +#define IDC_CODEC_SIZE 1011 +#define IDC_IPADDRESS1 1012 +#define IDC_LOCAL_PORT1 1013 +#define IDC_CHANGE_SIZE 1017 +#define IDC_QUALITY 1018 +#define IDC_BITRATE 1019 +#define IDC_WINDOW_SIZE 1022 +#define IDC_REMOTE_PORT1 1025 +#define IDC_START_REC 1030 +#define IDC_STOP_REC 1031 +#define IDC_CAM_PROPERTY 1033 +#define IDC_ONMODE 1034 +#define IDC_CAPTURECAP 1038 +#define IDC_RADIO1 1039 +#define IDC_MIN_FRAME_RATE 1040 +#define IDC_RTCPMODE 1042 +#define IDC_TMMBR 1043 +#define IDC_PACKETBURST 1044 +#define IDC_PROT_NONE 1045 +#define IDC_PROT_NACK 1046 +#define IDC_PROT_FEC 1047 +#define IDC_INFORMATION 1050 +#define IDC_PACKETLOSS 1051 +#define IDC_FREEZELOG 1052 +#define IDC_BUTTON1 1053 +#define IDC_CAMERACAP 1053 +#define IDC_EXTTRANSPORT 1054 +#define IDC_DELAY 1055 +#define IDC_BTN_RECORD_INCOMING 1056 +#define IDC_BTN_RECORD_OUTGOING 1057 +#define IDC_BUTTON2 1058 +#define IDC_BTN_CREATE_SLAVE 1058 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 133 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1059 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/video_engine/main/test/WindowsTest/tbExternalTransport.cpp b/video_engine/main/test/WindowsTest/tbExternalTransport.cpp new file mode 100644 index 0000000000..5839863e6e --- /dev/null +++ b/video_engine/main/test/WindowsTest/tbExternalTransport.cpp @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// tbExternalTransport.cpp +// + +#include "tbExternalTransport.h" + +#include "critical_section_wrapper.h" +#include "event_wrapper.h" +#include "thread_wrapper.h" +#include "tick_util.h" +#include "vie_network.h" +#include "tick_util.h" + +using namespace webrtc; + +tbExternalTransport::tbExternalTransport(ViENetwork& vieNetwork) + : + _vieNetwork(vieNetwork), + _thread(*ThreadWrapper::CreateThread(ViEExternalTransportRun, this, kHighPriority, "AutotestTransport")), + _event(*EventWrapper::Create()), + _crit(*CriticalSectionWrapper::CreateCriticalSection()), + _statCrit(*CriticalSectionWrapper::CreateCriticalSection()), + _lossRate(0), + _networkDelayMs(0), + _rtpCount(0), + _dropCount(0), + _rtcpCount(0), + _rtpPackets(), + _rtcpPackets(), + _checkSSRC(false), + _lastSSRC(0), + _checkSequenceNumber(0), + _firstSequenceNumber(0), + _lastSeq(0) +{ + srand((int)TickTime::MicrosecondTimestamp()); + unsigned int tId = 0; + _thread.Start(tId); +} + + +tbExternalTransport::~tbExternalTransport() +{ + // TODO: stop thread + _thread.SetNotAlive(); + _event.Set(); + if (_thread.Stop()) + { + delete &_thread; + delete &_event; + } + delete &_crit; + delete &_statCrit; +} + + + + + +int tbExternalTransport::SendPacket(int channel, const void *data, int len) +{ + _statCrit.Enter(); + _rtpCount++; + _statCrit.Leave(); + + + unsigned short sequenceNumber = (((unsigned char*) data)[2]) << 8; + sequenceNumber += (((unsigned char*) data)[3]); + + + int marker=((unsigned char*)data)[1] & 0x80; + unsigned int timestamp=((((unsigned char*)data)[4]) << 24) + ((((unsigned char*)data)[5])<<16) +((((unsigned char*)data)[6])<<8)+(((unsigned char*)data)[7]); + + + // Packet loss + int dropThis = rand() % 100; + bool nacked=false; + if(sequenceNumber<_lastSeq) + { + nacked=true; + } + else + { + _lastSeq=sequenceNumber; + } + + if (dropThis < _lossRate) + { + _statCrit.Enter(); + _dropCount++; + _statCrit.Leave(); + + + /* char str[256]; + sprintf(str,"Dropping seq %d length %d m %d, ts %u\n", sequenceNumber,len,marker,timestamp) ; + OutputDebugString(str);*/ + + return len; + } + else + { + if(nacked) + { + /*char str[256]; + sprintf(str,"Resending seq %d length %d m %d, ts %u\n", sequenceNumber,len,marker,timestamp) ; + OutputDebugString(str);*/ + } + else + { + /*char str[256]; + sprintf(str,"Sending seq %d length %d m %d, ts %u\n", sequenceNumber,len,marker,timestamp) ; + OutputDebugString(str);*/ + + } + } + + + VideoPacket* newPacket = new VideoPacket(); + memcpy(newPacket->packetBuffer, data, len); + newPacket->length = len; + newPacket->channel = channel; + + _crit.Enter(); + newPacket->receiveTime = NowMs() + _networkDelayMs; + _rtpPackets.push(newPacket); + _event.Set(); + _crit.Leave(); + return len; +} + +int tbExternalTransport::SendRTCPPacket(int channel, const void *data, int len) +{ + _statCrit.Enter(); + _rtcpCount++; + _statCrit.Leave(); + + VideoPacket* newPacket = new VideoPacket(); + memcpy(newPacket->packetBuffer, data, len); + newPacket->length = len; + newPacket->channel = channel; + + _crit.Enter(); + newPacket->receiveTime = NowMs() + _networkDelayMs; + _rtcpPackets.push(newPacket); + _event.Set(); + _crit.Leave(); + return len; +} + +WebRtc_Word32 tbExternalTransport::SetPacketLoss(WebRtc_Word32 lossRate) +{ + CriticalSectionScoped cs(_statCrit); + _lossRate = lossRate; + return 0; +} + +void tbExternalTransport::SetNetworkDelay(WebRtc_Word64 delayMs) +{ + CriticalSectionScoped cs(_crit); + _networkDelayMs = delayMs; + return; +} + +void tbExternalTransport::ClearStats() +{ + CriticalSectionScoped cs(_statCrit); + _rtpCount = 0; + _dropCount = 0; + _rtcpCount = 0; + return; +} + +void tbExternalTransport::GetStats(WebRtc_Word32& numRtpPackets, WebRtc_Word32& numDroppedPackets, WebRtc_Word32& numRtcpPackets) +{ + CriticalSectionScoped cs(_statCrit); + numRtpPackets = _rtpCount; + numDroppedPackets = _dropCount; + numRtcpPackets = _rtcpCount; + return; +} + +void tbExternalTransport::EnableSSRCCheck() +{ + CriticalSectionScoped cs(_statCrit); + _checkSSRC = true; +} +unsigned int tbExternalTransport::ReceivedSSRC() +{ + CriticalSectionScoped cs(_statCrit); + return _lastSSRC; +} + +void tbExternalTransport::EnableSequenceNumberCheck() +{ + CriticalSectionScoped cs(_statCrit); + _checkSequenceNumber = true; +} + +unsigned short tbExternalTransport::GetFirstSequenceNumber() +{ + CriticalSectionScoped cs(_statCrit); + return _firstSequenceNumber; +} + + +bool tbExternalTransport::ViEExternalTransportRun(void* object) +{ + return static_cast(object)->ViEExternalTransportProcess(); +} +bool tbExternalTransport::ViEExternalTransportProcess() +{ + unsigned int waitTime = KMaxWaitTimeMs; + + VideoPacket* packet = NULL; + + while (!_rtpPackets.empty()) + { + // Take first packet in queue + _crit.Enter(); + packet = _rtpPackets.front(); + WebRtc_Word64 timeToReceive = packet->receiveTime - NowMs(); + if (timeToReceive > 0) + { + // No packets to receive yet + if (timeToReceive < waitTime && + timeToReceive > 0) + { + waitTime = (unsigned int) timeToReceive; + } + _crit.Leave(); + break; + } + _rtpPackets.pop(); + _crit.Leave(); + + // Send to ViE + if (packet) + { + { + CriticalSectionScoped cs(_statCrit); + if (_checkSSRC) + { + _lastSSRC = ((packet->packetBuffer[8]) << 24); + _lastSSRC += (packet->packetBuffer[9] << 16); + _lastSSRC += (packet->packetBuffer[10] << 8); + _lastSSRC += packet->packetBuffer[11]; + _checkSSRC = false; + } + if (_checkSequenceNumber) + { + _firstSequenceNumber = (unsigned char)packet->packetBuffer[2] << 8; + _firstSequenceNumber += (unsigned char)packet->packetBuffer[3]; + _checkSequenceNumber = false; + } + } + /* + unsigned short sequenceNumber = (unsigned char)packet->packetBuffer[2] << 8; + sequenceNumber += (unsigned char)packet->packetBuffer[3]; + + int marker=packet->packetBuffer[1] & 0x80; + unsigned int timestamp=((((unsigned char*)packet->packetBuffer)[4]) << 24) + ((((unsigned char*)packet->packetBuffer)[5])<<16) +((((unsigned char*)packet->packetBuffer)[6])<<8)+(((unsigned char*)packet->packetBuffer)[7]); + char str[256]; + sprintf(str,"Receiving seq %u length %d m %d, ts %u\n", sequenceNumber,packet->length,marker,timestamp) ; + OutputDebugString(str);*/ + + _vieNetwork.ReceivedRTPPacket(packet->channel, packet->packetBuffer, packet->length); + delete packet; + packet = NULL; + } + } + while (!_rtcpPackets.empty()) + { + // Take first packet in queue + _crit.Enter(); + packet = _rtcpPackets.front(); + WebRtc_Word64 timeToReceive = packet->receiveTime - NowMs(); + if (timeToReceive > 0) + { + // No packets to receive yet + if (timeToReceive < waitTime && + timeToReceive > 0) + { + waitTime = (unsigned int) timeToReceive; + } + _crit.Leave(); + break; + } + packet = _rtcpPackets.front(); + _rtcpPackets.pop(); + _crit.Leave(); + + // Send to ViE + if (packet) + { + _vieNetwork.ReceivedRTCPPacket(packet->channel, packet->packetBuffer, packet->length); + delete packet; + packet = NULL; + } + } + _event.Wait(waitTime + 1); // Add 1 ms to not call to early... + return true; +} + +WebRtc_Word64 tbExternalTransport::NowMs() +{ + return TickTime::MillisecondTimestamp(); +} diff --git a/video_engine/main/test/WindowsTest/tbExternalTransport.h b/video_engine/main/test/WindowsTest/tbExternalTransport.h new file mode 100644 index 0000000000..85c2f6b19b --- /dev/null +++ b/video_engine/main/test/WindowsTest/tbExternalTransport.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// +// tbExternalTransport.h +// + +#ifndef WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_TBEXTERNALTRANSPORT_H_ +#define WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_TBEXTERNALTRANSPORT_H_ + +#include "common_types.h" +#include + +namespace webrtc +{ +class CriticalSectionWrapper; +class EventWrapper; +class ThreadWrapper; +class ViENetwork; +} + +class tbExternalTransport : public webrtc::Transport +{ +public: + tbExternalTransport(webrtc::ViENetwork& vieNetwork); + ~tbExternalTransport(void); + + virtual int SendPacket(int channel, const void *data, int len); + virtual int SendRTCPPacket(int channel, const void *data, int len); + + WebRtc_Word32 SetPacketLoss(WebRtc_Word32 lossRate); // Rate in % + void SetNetworkDelay(WebRtc_Word64 delayMs); + + void ClearStats(); + void GetStats(WebRtc_Word32& numRtpPackets, WebRtc_Word32& numDroppedPackets, WebRtc_Word32& numRtcpPackets); + + void EnableSSRCCheck(); + unsigned int ReceivedSSRC(); + + void EnableSequenceNumberCheck(); + unsigned short GetFirstSequenceNumber(); + + +protected: + static bool ViEExternalTransportRun(void* object); + bool ViEExternalTransportProcess(); +private: + WebRtc_Word64 NowMs(); + + enum { KMaxPacketSize = 1650}; + enum { KMaxWaitTimeMs = 100}; + typedef struct + { + WebRtc_Word8 packetBuffer[KMaxPacketSize]; + WebRtc_Word32 length; + WebRtc_Word32 channel; + WebRtc_Word64 receiveTime; + } VideoPacket; + + typedef std::queue VideoPacketQueue; + + + webrtc::ViENetwork& _vieNetwork; + webrtc::ThreadWrapper& _thread; + webrtc::EventWrapper& _event; + webrtc::CriticalSectionWrapper& _crit; + webrtc::CriticalSectionWrapper& _statCrit; + + WebRtc_Word32 _lossRate; + WebRtc_Word64 _networkDelayMs; + WebRtc_Word32 _rtpCount; + WebRtc_Word32 _rtcpCount; + WebRtc_Word32 _dropCount; + + VideoPacketQueue _rtpPackets; + VideoPacketQueue _rtcpPackets; + + bool _checkSSRC; + WebRtc_UWord32 _lastSSRC; + bool _checkSequenceNumber; + WebRtc_UWord16 _firstSequenceNumber; + WebRtc_Word32 _lastSeq; + + //int& numberOfErrors; + + //int _bits; + //int _lastTicks; + //int _dropCnt; + //int _sentCount; + //int _frameCount; + //int _packetLoss; + + //VideoEngine* _video; + + //ReceiveBufferQueue _videoBufferQueue; + //ReceiveBufferQueue _rtcpBufferQueue; +}; + +#endif // WEBRTC_VIDEO_ENGINE_MAIN_TEST_WINDOWSTEST_TBEXTERNALTRANSPORT_H_ diff --git a/video_engine/main/test/WindowsTest/videosize.cpp b/video_engine/main/test/WindowsTest/videosize.cpp new file mode 100644 index 0000000000..a675ec5ff7 --- /dev/null +++ b/video_engine/main/test/WindowsTest/videosize.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "VideoSize.h" +int GetWidthHeight( VideoSize size, int& width, int& height) +{ + switch(size) + { + case SQCIF: + width = 128; + height = 96; + return 0; + case QQVGA: + width = 160; + height = 120; + return 0; + case QCIF: + width = 176; + height = 144; + return 0; + case CGA: + width = 320; + height = 200; + return 0; + case QVGA: + width = 320; + height = 240; + return 0; + case SIF: + width = 352; + height = 240; + return 0; + case WQVGA: + width = 400; + height = 240; + return 0; + case CIF: + width = 352; + height = 288; + return 0; + case W288P: + width = 512; + height = 288; + return 0; + case W368P: + width = 640; + height = 368; + return 0; + case S_448P: + width = 576; + height = 448; + return 0; + case VGA: + width = 640; + height = 480; + return 0; + case S_432P: + width = 720; + height = 432; + return 0; + case W432P: + width = 768; + height = 432; + return 0; + case S_4SIF: + width = 704; + height = 480; + return 0; + case W448P: + width = 768; + height = 448; + return 0; + case NTSC: + width = 720; + height = 480; + return 0; + case FW448P: + width = 800; + height = 448; + return 0; + case S_768x480P: + width = 768; + height = 480; + return 0; + case WVGA: + width = 800; + height = 480; + return 0; + case S_4CIF: + width = 704; + height = 576; + return 0; + case SVGA: + width = 800; + height = 600; + return 0; + case W544P: + width = 960; + height = 544; + return 0; + case W576P: + width = 1024; + height = 576; + return 0; + case HD: + width = 960; + height = 720; + return 0; + case XGA: + width = 1024; + height = 768; + return 0; + case FULL_HD: + width = 1440; + height = 1080; + return 0; + case WHD: + width = 1280; + height = 720; + return 0; + case UXGA: + width = 1600; + height = 1200; + return 0; + case WFULL_HD: + width = 1920; + height = 1080; + return 0; + default: + return -1; + } + return -1; +} \ No newline at end of file diff --git a/video_engine/main/test/WindowsTest/windowstest.gyp b/video_engine/main/test/WindowsTest/windowstest.gyp new file mode 100644 index 0000000000..486083f4ca --- /dev/null +++ b/video_engine/main/test/WindowsTest/windowstest.gyp @@ -0,0 +1,73 @@ +{ + 'includes': [ + '../../../../common_settings.gypi', # Common settings + ], + 'conditions': [ + ['OS=="win"', { + 'targets': [ + # WinTest - GUI test for Windows + { + 'target_name': 'vie_win_test', + 'type': 'executable', + 'dependencies': [ + '../../../../system_wrappers/source/system_wrappers.gyp:system_wrappers', # need the headers + '../../../../modules/video_render/main/source/video_render.gyp:video_render_module', + '../../../../modules/video_capture/main/source/video_capture.gyp:video_capture_module', + ## VoiceEngine + '../../../../voice_engine/main/source/voice_engine_core.gyp:voice_engine_core', + ## VideoEngine + '../../source/video_engine_core.gyp:video_engine_core', + ], + 'include_dirs': [ + './interface', + '../../../../', # common_types.h and typedefs.h + '../commonTestClasses/' + ], + 'sources': [ + 'Capture.rc', + 'captureDeviceImage.jpg', + 'ChannelDlg.cpp', + 'ChannelDlg.h', + 'ChannelPool.cpp', + 'ChannelPool.h', + 'renderStartImage.jpg', + 'renderTimeoutImage.jpg', + 'res\Capture.rc2', + 'resource.h', + 'StdAfx.h', + 'videosize.cpp', + 'VideoSize.h', + 'WindowsTest.cpp', + 'WindowsTest.h', + 'WindowsTestMainDlg.cpp', + 'WindowsTestMainDlg.h', + 'WindowsTestResouce.rc', + 'WindowsTestResource.h', + 'tbExternalTransport.cpp', + 'CaptureDevicePool.cpp', + 'tbExternalTransport.h', + 'CaptureDevicePool.h', + + ], + 'configurations': { + 'Common_Base': { + 'msvs_configuration_attributes': { + 'UseOfMFC': '1', # Static + }, + }, + }, + 'msvs_settings': { + 'VCLinkerTool': { + 'SubSystem': '2', # Windows + }, + }, + }, + ], + }], + ], +} +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: