Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Example of Android application to publish device screen

The example shows how to share device screen

...

Image Removed. Device microphone or (in Android 10 or above) system audio may also be captured.

Image Added

Work with example code

To analyze the code let's take the class ScreenSharingActivity.java of the screen-sharing example, which can be downloaded with build1.1.0.5564.

1. Initialization of the API.

Flashphoner.init() code

Context object is passed to method init() for initialization.

Code Block
languagejava
themeRDark
Flashphoner.init(this);

2. Request the permission to use microphoneDisplay or hide a system sound capture button depending on Android version

code

Code Block
languagejava
themeRDark
        if mMicCheckBox.setOnClickListener(new View.OnClickListener() (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            @OverridemAudioRadioGroup.setVisibility(View.VISIBLE);
            public void onClick(View v) } else {
                if (mMicCheckBox.isChecked()) {mAudioRadioGroup.setVisibility(View.GONE);

                    ActivityCompat.requestPermissions(ScreenSharingActivity.this,}

3. Request the permission to capture audio

code

Code Block
languagejava
themeRDark
        mUseAudioCheckBox.setOnClickListener(v -> {
            if (mUseAudioCheckBox.isChecked()) {
               new String[]{Manifest.permission.RECORD_AUDIO}ActivityCompat.requestPermissions(ScreenSharingActivity.this,
                            PUBLISH_REQUEST_CODE);
new String[]{Manifest.permission.RECORD_AUDIO},
                  }      PUBLISH_REQUEST_CODE);
            }
        });

34. Choose the microphone

code

Code Block
languagejava
themeRDark
        mMicSpinner = (Spinner) findViewById(R.id.spinner_mic);
        ArrayAdapter<MediaDevice> arrayAdapter = new ArrayAdapter<MediaDevice>(this, android.R.layout.simple_spinner_item, Flashphoner.getMediaDevices().getAudioList());
        arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        mMicSpinner.setAdapter(arrayAdapter);

45. Session creation

Flashphoner.createSession() code

SessionOptions is passed to the method with the following parameters

...

Code Block
languagejava
themeRDark
                    SessionOptions sessionOptions = new SessionOptions(url);
                    sessionOptions.setLocalRenderer(localRender);
                    sessionOptions.setRemoteRenderer(remoteRender);

                    /**
                     * Session for connection to WCS server is created with method createSession().
                     */
                    session = Flashphoner.createSession(sessionOptions);

56. Connection to the server

Session.connect() code

Code Block
languagejava
themeRDark
session.connect(new Connection());

67.   Receiving the event confirming successful connection.

session.onConnected() code

Code Block
languagejava
themeRDark
@Override
public void onConnected(final Connection connection) {
    runOnUiThread(new Runnable() -> {
       @Override mStartButton.setText(R.string.action_stop);
       public void run() { mStartButton.setTag(R.string.action_stop);
           mStartButtonmStatusView.setText(R.string.action_stopconnection.getStatus());
    });
       mStartButton.setTag(R.string.action_stop);
...
}

8. Video stream creation

session.createStream() code

Code Block
languagejava
themeRDark
             mStartButton.setEnabled(true);
           mStatusView.setText(connection.getStatus());
           ...
      StreamOptions }
streamOptions = new }StreamOptions(streamName);
}

7. Video stream creation

session.createStream() code

Code Block
languagejava
themeRDark
                                    StreamOptionsVideoConstraints streamOptionsvideoConstraints = new StreamOptionsVideoConstraints(streamName);
                                    VideoConstraints videoConstraints = new VideoConstraints();
                                    DisplayMetrics DisplayMetrics metrics = getResources().getDisplayMetrics();
                                    videoConstraints.setResolution(metrics.widthPixels, metrics.heightPixels);
                                    videoConstraints.setVideoFps(metrics.densityDpi);
                                    streamOptions.getConstraints().setVideoConstraints(videoConstraints);
                                    streamOptions.getConstraints().updateAudio(mMicCheckBoxmUseAudioCheckBox.isChecked());

                                    /**
                                     * Stream is created with method Session.createStream().
                                     */
                                    publishStream = session.createStream(streamOptions);
                                    ...
                                    startScreenCapture();

89. Prepare to capture device screen

...

Code Block
languagejava
themeRDark
    private void startScreenCapture() {
        mMediaProjectionManager = (MediaProjectionManager) getSystemService(
                Context.MEDIA_PROJECTION_SERVICE);
        Intent permissionIntent = mMediaProjectionManager.createScreenCaptureIntent();
        startActivityForResult(permissionIntent, REQUEST_CODE_CAPTURE_PERM);
    }

910. Start foreground service, capture the screen and publish the stream

startService(), setVideoCapturer(), Stream.publish() code

context.startForegroundService() code

Code Block
languagejava
themeRDark
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (REQUEST_CODE_CAPTURE_PERM == requestCode && resultCode == RESULT_OK) {

            serviceIntentthis.mediaProjectionData = data;

 new Intent(this, ScreenSharingService.class);
         Context context = startServicegetApplicationContext(serviceIntent);
            videoCapturer       this.serviceIntent = new ScreenCapturerAndroidIntent(datacontext, new MediaProjection.Callback() {ScreenSharingService.class);
            context.startForegroundService(serviceIntent);
    @Override
    } else {
          public void onStoprunOnUiThread(() { -> mStartButton.setEnabled(false));
                    super.onStopstop();
                }
            }Log.i(TAG, "Permission has been denied by user");
        }
    WebRTCMediaProvider.getInstance}

11. Capture device screen and publish a stream

ScreenCapturerAndroid(), Stream.

...

publish(

...

) code

Code Block
languagejava
themeRDark
    private final BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
  /**
      @Override
        *public Methodvoid Stream.publish() is called to publish stream.
onReceive(Context context, Intent intent) {
            if (intent != null) {
     */
            publishStream.publish();
if (ScreenSharingService.ACTION_START.equals(intent.getAction())) {
              Log.i(TAG, "Permission has been granted by user");
MediaProjection mediaProjection = null;
         ...
        }
   if }

10. Receiving the event confirming the successful stream publishing

StreamStatusEvent PUBLISHING code

On receiving this event preview stream is created with Session.createStream() and Stream.play() is invoked to play it.

Code Block
languagejava
themeRDark
   (mUseAudioCheckBox.isChecked() && !mUseMicRadioButton.isChecked() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                        mediaProjection         publishStream.on(new StreamStatusEvent() {= mediaProjectionManager.getMediaProjection(Activity.RESULT_OK, mediaProjectionData);
                    }

                    @Override
 WebRTCMediaProvider.getInstance().setMediaProjection(mediaProjection);
                    videoCapturer = new ScreenCapturerAndroid(mediaProjection, mediaProjectionData,               public void onStreamStatus(final Stream stream, final StreamStatus streamStatus) {
new MediaProjection.Callback() {
                        @Override
                        public runOnUiThread(newvoid RunnableonStop() {
                            super.onStop();
                    @Override
        handler.post(ScreenSharingActivity.this::stop);
                        }
                  public void run(}) {;
                    WebRTCMediaProvider.getInstance().setVideoCapturer(videoCapturer);

                    publishStream.publish();
                } else if (StreamStatusScreenSharingService.PUBLISHINGACTION_STOP.equals(streamStatusintent.getAction())) {

                      handler.post(ScreenSharingActivity.this::stop);
                }
                  /**}
        }
                           };

12. Receiving the event confirming the successful stream publishing

StreamStatus.PUBLISHING code

On receiving this event preview stream is created with Session.createStream() and Stream.play() is invoked to play it.

Code Block
languagejava
themeRDark
                      * The options for the stream to play are set.
     publishStream.on(new StreamStatusEvent() {
                                        @Override
          * The stream name is passed when StreamOptions object is created.
                    public void onStreamStatus(final Stream stream, final StreamStatus streamStatus) {
                             */
               runOnUiThread(new Runnable() {
                                       StreamOptions streamOptions = new StreamOptions(streamName);
     @Override
                                                public void  streamOptions.getConstraints().updateAudio(mMicCheckBox.isChecked());

run() {
                                                    if (StreamStatus.PUBLISHING.equals(streamStatus)) {

   /**
                                                      /**
   * Stream is created with method Session.createStream().
                                                * The options for the stream to play are */set.
                                                        playStream = session.createStream(streamOptions);
         * The stream name is passed when StreamOptions object is created.
                                               ...
          */
                                              playStream.play();
          StreamOptions streamOptions = new StreamOptions(streamName);
                                      } else {
                streamOptions.getConstraints().updateAudio(mMicCheckBox.isChecked());

                                        Log.e(TAG, "Can not publish stream " + stream.getName() + " " + streamStatus);
    /**
                                                }
         * Stream is created with   method Session.createStream().
                                                         mStatusView.setText(streamStatus.toString());*/
                                                }
        playStream = session.createStream(streamOptions);
                                    });
                    ...
                    }
                                    });

11. Session disconnection.

Session.disconnect() code

Code Block
languagejava
themeRDark
mStartButton.setEnabled(false);

/**
  * Connection to WCS server is closed with method Session.disconnect().
  */
session.disconnect();

12. Starting foreground service

Service.onCreate(), startForeground() code

Code Block
languagejava
themeRDark
    @Override
    public void onCreate() {playStream.play();
                                                    } else {
                                                        Log.e(TAG, "Can not publish stream " + stream.getName() + " " + streamStatus);
                                                    }
                                                    mStatusView.setText(streamStatus.toString());
                                                }
                                            });
                                        }
                                    });

13. Session disconnection.

Session.disconnect() code

Code Block
languagejava
themeRDark
    private synchronized void stop() {
        if (session != null) {
            session.disconnect();
            session = null;
        }

        WebRTCMediaProvider.getInstance().releaseLocalMediaAccess();

        if (serviceIntent != null) {
            stopService(serviceIntent);
            this.serviceIntent = null;
        super.onCreate();}

        NotificationChannel chan =...
    }

14. Foreground service creation

Service.onCreate(), startForeground() code

Code Block
languagejava
themeRDark
    @Override
    public void   new NotificationChannel(
  onCreate() {
        super.onCreate();

        NotificationChannel chan = new   NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_NONE);
        chan.setImportance(NotificationManager.IMPORTANCE_MIN);

        NotificationManager manager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        manager.createNotificationChannel(chan);

        final int notificationId = (int) System.currentTimeMillis();
        NotificationCompat.Builder notificationBuilder =
      = (int) System.currentTimeMillis();
        Notification.Builder notificationBuilder = new NotificationCompatNotification.Builder(this, CHANNEL_ID);
        Notification notification =
                notificationBuilder
                        .setSmallIcon(R.drawable.service_icon)
                        .setOngoing(true)
                        .setShowWhen(true)
                        .setContentTitle("ScreenSharingService is running in the foreground")
                        .setPrioritysetCategory(NotificationManagerNotification.IMPORTANCECATEGORY_MINSERVICE)
                        .setCategory(Notification.CATEGORY_SERVICEaddAction(createStopAction())
                        .build();  .build();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        NotificationManager notificationManager
   startForeground(notificationId, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
        } else {
 =  (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(NOTIFICATION_IDstartForeground(notificationId, notification);

        startForeground(notificationId, notification);}
    }

1315. Stopping foreground service

Service.onDestroy(), stopForeground() code

Code Block
languagejava
themeRDark
    @Override
    public void onDestroy() {
        stopForeground(true);
        super.onDestroy();
    }