Implement screen sharing on Windows

更新时间:
复制 MD 格式

This topic describes how to implement screen sharing on Windows.

Overview

Screen sharing allows users to share their screen content in real time with other users in a channel during video calls or live streaming, enabling instant information sharing.

Sample project

ARTC provides an open-source sample project. You can download the project or view the code samples here: Implement screen sharing on Windows.

Prerequisites

Ensure that you meet the following prerequisites:

Implement screen sharing

image
Note
  • For ARTC versions earlier than 7.6, you must join a channel before you can start screen sharing. For instructions on how to join a channel, see Implement an audio/video call.

  • Starting with ARTC version 7.6, you can start screen sharing without first joining a channel. We recommend first setting AliEngineScreenShareConfig.isPushStream to FALSE. After joining the channel, set it to TRUE and call UpdateScreenShareConfig to start stream publishing.

1. Configure encoding parameters

To customize the encoding parameters for the screen sharing stream, call the setScreenShareEncoderConfiguration API to configure properties such as resolution, frame rate, bitrate, GOP, and video orientation.

Note
  • You can call this API both before and after joining a channel. If you only need to set the encoding parameters once per session, we recommend calling it before joining the channel.

  • To update the configuration, you can call this API multiple times.

The following table describes the parameters.

Parameter

Description

Default

dimensions

Video resolution.

0x0, which means the publishing resolution matches the captured screen resolution. The maximum value is 3840x2160.

frameRate

Video frame rate.

The default frame rate is 5 fps. The maximum value is 30 fps.

bitrate

Video encoding bitrate in Kbps.

Note

The bitrate has a recommended range that corresponds to the resolution and frame rate. If you set a value outside this range, the SDK automatically adjusts the bitrate to a suitable value.

512

keyFrameInterval

The keyframe interval (GOP) in milliseconds (ms).

0, which means the SDK controls the keyframe interval internally.

forceStrictKeyFrameInterval

Specifies whether to force the encoder to generate keyframes strictly at the set interval.

false

  • false: The encoder responds to requests for keyframes, such as when a new user joins. The actual keyframe interval might not strictly match the set value.

  • true: The encoder does not respond to other keyframe requests and strictly adheres to the set interval. This may delay rendering the first frame for subscribers.

rotationMode

The rotation of the published stream.

The default value is AliEngineRotationMode_0. You can choose 0, 90, 180, or 270 degrees.

/* 
  'config' is a user-defined configuration struct. 
*/

AliEngineScreenShareEncoderConfiguration encoderConfig;

encoderConfig.dimensions = AliEngineVideoDimensions(config.dimensions.width, config.dimensions.height);
encoderConfig.frameRate = (AliEngineFrameRate)config.frameRate;
encoderConfig.bitrate = (int)config.bitrate;
encoderConfig.rotationMode = (AliEngineRotationMode)config.rotationMode;
encoderConfig.keyFrameInterval = (int)config.keyFrameInterval;
encoderConfig.forceStrictKeyFrameInterval = config.forceStrictKeyFrameInterval;
   
mpEngine->SetScreenShareEncoderConfiguration(encoderConfig);

2. Configure the preview

To preview the screen sharing content, call SetLocalViewConfig to configure the display view for the screen sharing stream (AliEngineVideoTrackScreen).

AliEngineVideoCanvas canvas;
canvas.renderMode = AliEngineRenderModeFill;
/* Configure the window handle for display. */
canvas.displayView = (void*)hWnd;
canvas.scaleMode = AliEngineVideoScale_16_9;

mpEngine->SetLocalViewConfig(canvas, AliEngineVideoTrackScreen);

3. View a remote screen share

To view a remote user's screen share, call SetRemoteViewConfig to configure the display view for the screen sharing stream in the OnRemoteTrackAvailableNotify callback.

void ARTCEventListernerImpl::OnRemoteTrackAvailableNotify(const char *uid,
	AliEngineAudioTrack audioTrack,
	AliEngineVideoTrack videoTrack) {

	char logBuffer[MAX_LOG_STRING_SIZE];
	snprintf(logBuffer, USE_LOG_STRING_SIZE, "user %s push video=%d audio=%d", uid, videoTrack, audioTrack);
	SendMessageA(this->mLogHandle, LB_ADDSTRING, WPARAM(), (LPARAM)logBuffer);

	mDlg->HandleTrackChangeEvent(uid, audioTrack, videoTrack);

}

void CARTCExampleDlg::HandleTrackChangeEvent(const char *uid,
	AliEngineAudioTrack audioTrack,
	AliEngineVideoTrack videoTrack) {

	if ((videoTrack & AliEngineVideoTrackScreen) > 0) {

		if ((videoTrack & AliEngineVideoTrackCamera) == 0) {

			AliEngineVideoCanvas canvas;
			canvas.displayView = nullptr;

			mEngine->SetRemoteViewConfig(canvas, uid, AliEngineVideoTrackCamera);
		}


		{
			AliEngineVideoCanvas canvas;
			canvas.displayView = mRemoteView.GetSafeHwnd();

			mEngine->SetRemoteViewConfig(canvas, uid, AliEngineVideoTrackScreen);
		}

		return;
	}

	if ( (videoTrack & AliEngineVideoTrackCamera) > 0) {

		AliEngineVideoCanvas canvas;
		canvas.displayView = mRemoteView.GetSafeHwnd();

		mEngine->SetRemoteViewConfig(canvas, uid, AliEngineVideoTrackCamera );
	}
}

4. Start screen sharing

Call StartScreenShareByScreenRegion to start screen sharing.

Note

You need to configure mScreenConfig.isPushStream.

/*
* Share a region of the screen.
*/
  RECT rc;
  ::GetWindowRect(::GetDesktopWindow(), &rc);

  AliEngineScreenShareRegion screenRegion;
  screenRegion.originX = (float)rc.left;
  screenRegion.originY = (float)rc.top;
  screenRegion.width = (float)(rc.right - rc.left);
  screenRegion.height = (float)(rc.bottom - rc.top);

  AliEngineScreenShareConfig mScreenConfig;
  mScreenConfig.isShareByRegion = false;
  mScreenConfig.shareRegion = screenRegion;
  /* 
    If you only want to preview the stream without publishing it, set this to FALSE.
    If you want to preview and publish simultaneously, set this to TRUE. This allows you to skip Step 5 (Update configuration) and start publishing directly.
  */        
  mScreenConfig.isPushStream = FALSE ; 
  
  mpEngine->StartScreenShareByScreenRegion(screenRegion, mScreenConfig);

5. (Optional) Update the configuration

To update the screen sharing configuration, call UpdateScreenShareConfig.

/* Set to publish the screen sharing stream. */
mScreenConfig.isPushStream = TRUE ;

/* To share a region: */
mScreenConfig.isShareByRegion = true ;

screenRegion.originX = (float)rc.left;
screenRegion.originY = (float)rc.top;
screenRegion.width = (float)(rc.right - rc.left);
screenRegion.height = (float)(rc.bottom - rc.top);

mScreenConfig.isShareByRegion = true;
mScreenConfig.shareRegion = screenRegion;
      
mpEngine->UpdateScreenShareConfig(mScreenConfig);

6. Stop screen sharing

mpEngine->StopScreenShare();

Multi-window sharing

The basic logic for configuring the preview window, previewing, and stream publishing is the same as for screen sharing, so the code is omitted.

1. Enumerate all shareable windows or desktops

Call GetScreenShareSourceInfo to get a list of shareable windows and desktops.

/*
  1. Set the enumeration type as needed.
*/
mScreenShareType = AliEngineScreenShareDesktop ; 
mScreenShareType = AliEngineScreenShareWindow ; 

/*
 2. The following code populates a combo box list.
*/
CComboBox *listBox = (CComboBox *)GetDlgItem(IDC_COMBO_SCREEN_SOURCE_LIST);
listBox->ResetContent();

AliEngineScreenSourceList* mCurrentSourceList = mEngine->GetScreenShareSourceInfo(mScreenShareType);

  if (nullptr != mCurrentSourceList)
  {
      for (size_t i = 0; i < mCurrentSourceList->GetCount(); i++) {
      
        AliEngineScreenSourcInfo info = mCurrentSourceList->GetSourceInfo(i);

        /*
        * To exclude the application's own window from being shared, you can use `sourceIsSelf` to filter it out.
        */
        if ( info.sourceIsSelf ) {
           continue ;
        }
        
        CString s = AliStringToCString(info.sourceName);
        listBox->AddString(s)
      }    
      
  }

  /*
  3. After an item is selected, record its ID and title.
  */
  int idx = listBox->GetCurSel();
  
  if (mCurrentSourceList && idx < mCurrentSourceList->GetCount())
  {
    AliEngineScreenSourcInfo info = mCurrentSourceList->GetSourceInfo(idx);
    mSourceId = info.sourceId;
    mSourceTitle = info.sourceName;
  }

2. Share the selected window or desktop

Call either StartScreenShareByWindowId or StartScreenShareByDesktopId to share the selected window or desktop.

// msSourceId is the ID of the desktop to share, which can be obtained through the enumeration API described above.
// screenShareSource is the configuration object.

AliEngineScreenShareRegion  shareRegion ;
shareRegion.originX = 0.f;
shareRegion.originY = 0.f;
shareRegion.width = 640.f;
shareRegion.height = 480.f;
            
screenShareSource.isShareByRegion = true ;
screenShareSource.shareRegion =  shareRegion;

  /*
  * To preview without publishing the stream, set isPushStream=FALSE as described in the screen sharing section.
  */


/*
* Based on your product requirements, call the appropriate API to share a desktop or a window.
* Share a desktop:
*/
mpEngine->StartScreenShareByDesktopId(atol(msSourceId.c_str()), screenShareSource);

/*
* Or, share a window:
*/
mpEngine->StartScreenShareByWindowId(atol(msSourceId.c_str()), screenShareSource);

/*
* You can retrieve and display the region and title of the shared window.
*/
AliEngineScreenShareRegion region;
		mEngine->GetDesktopRegion(mSourceId, mSourceTitle, region);
		CString resolutionMsg;
		resolutionMsg.Format(_T("Resolution: %d x %d"), region.width, region.height);
		((CStatic*)GetDlgItem(IDC_STATIC_SCREEN_SOURCE_RESOLUTION))->SetWindowTextW(resolutionMsg);
		((CEdit*)GetDlgItem(IDC_EDIT_SHARE_REGION_X))->SetWindowTextW(std::to_wstring(mScreenShareSource.shareRegion.originX).c_str());
		((CEdit*)GetDlgItem(IDC_EDIT_SHARE_REGION_Y))->SetWindowTextW(std::to_wstring(mScreenShareSource.shareRegion.originY).c_str());
		((CEdit*)GetDlgItem(IDC_EDIT_SHARE_REGION_X2))->SetWindowTextW(std::to_wstring(mScreenShareSource.shareRegion.width).c_str());
		((CEdit*)GetDlgItem(IDC_EDIT_SHARE_REGION_Y2))->SetWindowTextW(std::to_wstring(mScreenShareSource.shareRegion.height).c_str());
	}
  

3. Stop sharing the window or desktop

mpEngine->StopScreenShare();