Does appium UiAutomator2 mjpeg server always start on port 7810?

According to documentation https://github.com/appium/appium-uiautomator2-driver#mjpeg, if capability appium:mjpegServerPort is not set, screenshot broadcast is not started.

Question 1

But from my test on Android 6.0.1, Appium UiAutomator2 mjpeg server starts even though capability appium:mjpegServerPort is not set. Does it mean the UiAutomator2 mjpeg server always starts regardless of capabilities?

from appium import webdriver
from datetime import datetime
deviceName = 'm4'
caps = dict(
            platformName = 'Android',
            automationName = 'uiautomator2',
            udid = deviceName + ':5555',
            mjpegScreenshotUrl = f'http://{deviceName}:7810',
            newCommandTimeout = 600,
            noReset = True
        )
driver = webdriver.Remote('http://localhost:4723/wd/hub', caps)
driver.get_screenshot_as_file(f'/home/k/Pictures/screenshot/{deviceName}-{datetime.now().strftime("%Y-%m-%d-%H-%M-%S-%f")}.png')
driver.get_settings()
driver.quit()
2021-03-22 21:32:07:982 [UiAutomator2] Starting MJPEG stream reading URL: 'http://m4:7810'
2021-03-22 21:32:07:983 [Support] Loading local package 'mjpeg-consumer'

driver.get_settings() returns

{'imageMatchThreshold': 0.4,
 'fixImageFindScreenshotDims': True,
 'fixImageTemplateSize': False,
 'fixImageTemplateScale': False,
 'defaultImageTemplateScale': 1,
 'checkForImageElementStaleness': True,
 'autoUpdateImageElementPosition': False,
 'imageElementTapStrategy': 'w3cActions',
 'getMatchedImageResult': False,
 'ignoreUnimportantViews': False,
 'allowInvisibleElements': False,
 'keyInjectionDelay': 0,
 'mjpegScalingFactor': 50,
 'trackScrollEvents': True,
 'normalizeTagNames': False,
 'useResourcesForOrientationDetection': False,
 'mjpegServerScreenshotQuality': 50,
 'wakeLockTimeout': 85965217,
 'waitForSelectorTimeout': 10000,
 'mjpegServerPort': 7810,
 'simpleBoundsCalculation': False,
 'shutdownOnPowerDisconnect': True,
 'scrollAcknowledgmentTimeout': 200,
 'mjpegServerFramerate': 10,
 'elementResponseAttributes': '',
 'enableMultiWindows': False,
 'actionAcknowledgmentTimeout': 3000,
 'serverPort': 6790,
 'waitForIdleTimeout': 10000,
 'enableNotificationListener': True,
 'mjpegBilinearFiltering': False,
 'shouldUseCompactResponses': True}

Full appium server debug log

Question 2

According to documentation https://github.com/appium/appium-uiautomator2-driver#mjpeg, capability appium:mjpegServerPort is the number of the port UiAutomator2 server starts the MJPEG server on.
If I set capability mjpegServerPort to a custom port 12345, the UiAutomator2 mjpeg server still starts on port 7810. How can I set a custom port?

Test case 2.1

mjpegServerPort = 12345, mjpegScreenshotUrl port is 12345

from appium import webdriver
from datetime import datetime
deviceName = 'm4'
caps = dict(
            platformName = 'Android',
            automationName = 'uiautomator2',
            udid = deviceName + ':5555',
            mjpegServerPort = 12345,
            mjpegScreenshotUrl = f'http://{deviceName}:12345',
            newCommandTimeout = 600,
            noReset = True
        )
driver = webdriver.Remote('http://localhost:4000/wd/hub', caps)

Port 12345 is not up.

2021-03-22 21:45:36:668 - [UiAutomator2] Starting MJPEG stream reading URL: 'http://m4:12345'
2021-03-22 21:45:36:678 - [Support] Error getting MJpeg screenshot chunk: connect 
...
ECONNREFUSED 192.168.31.140:12345
Unhandled rejection Error: connect ECONNREFUSED 192.168.31.140:12345
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1144:16)

driver.get_settings() returns

{'imageMatchThreshold': 0.4,
 'fixImageFindScreenshotDims': True,
 'fixImageTemplateSize': False,
 'fixImageTemplateScale': False,
 'defaultImageTemplateScale': 1,
 'checkForImageElementStaleness': True,
 'autoUpdateImageElementPosition': False,
 'imageElementTapStrategy': 'w3cActions',
 'getMatchedImageResult': False,
 'ignoreUnimportantViews': False,
 'allowInvisibleElements': False,
 'keyInjectionDelay': 0,
 'mjpegScalingFactor': 50,
 'trackScrollEvents': True,
 'normalizeTagNames': False,
 'useResourcesForOrientationDetection': False,
 'mjpegServerScreenshotQuality': 50,
 'wakeLockTimeout': 86267545,
 'waitForSelectorTimeout': 10000,
 'mjpegServerPort': 12345,
 'simpleBoundsCalculation': False,
 'shutdownOnPowerDisconnect': True,
 'scrollAcknowledgmentTimeout': 200,
 'mjpegServerFramerate': 10,
 'elementResponseAttributes': '',
 'enableMultiWindows': False,
 'actionAcknowledgmentTimeout': 3000,
 'serverPort': 6790,
 'waitForIdleTimeout': 10000,
 'enableNotificationListener': True,
 'mjpegBilinearFiltering': False,
 'shouldUseCompactResponses': True}

Test case 2.2

mjpegServerPort = 12345, mjpegScreenshotUrl port is 7810

from appium import webdriver
from datetime import datetime
deviceName = 'm4'
caps = dict(
            platformName = 'Android',
            automationName = 'uiautomator2',
            udid = deviceName + ':5555',
            mjpegServerPort = 12345,
            mjpegScreenshotUrl = f'http://{deviceName}:7810',
            newCommandTimeout = 600,
            noReset = True
        )
driver = webdriver.Remote('http://localhost:4000/wd/hub', caps)

Port 7810 is up.

2021-03-22 21:51:06:268 - [UiAutomator2] Starting MJPEG stream reading URL: 'http://m4:7810'
2021-03-22 21:51:06:625 - [Appium] New AndroidUiautomator2Driver session created successfully, session c20bc8b8-a9d4-427f-a15f-b3fbc2cd358a added to master session list

driver.get_settings() returns

{'imageMatchThreshold': 0.4,
 'fixImageFindScreenshotDims': True,
 'fixImageTemplateSize': False,
 'fixImageTemplateScale': False,
 'defaultImageTemplateScale': 1,
 'checkForImageElementStaleness': True,
 'autoUpdateImageElementPosition': False,
 'imageElementTapStrategy': 'w3cActions',
 'getMatchedImageResult': False,
 'ignoreUnimportantViews': False,
 'allowInvisibleElements': False,
 'keyInjectionDelay': 0,
 'mjpegScalingFactor': 50,
 'trackScrollEvents': True,
 'normalizeTagNames': False,
 'useResourcesForOrientationDetection': False,
 'mjpegServerScreenshotQuality': 50,
 'wakeLockTimeout': 86394189,
 'waitForSelectorTimeout': 10000,
 'mjpegServerPort': 12345,
 'simpleBoundsCalculation': False,
 'shutdownOnPowerDisconnect': True,
 'scrollAcknowledgmentTimeout': 200,
 'mjpegServerFramerate': 10,
 'elementResponseAttributes': '',
 'enableMultiWindows': False,
 'actionAcknowledgmentTimeout': 3000,
 'serverPort': 6790,
 'waitForIdleTimeout': 10000,
 'enableNotificationListener': True,
 'mjpegBilinearFiltering': False,
 'shouldUseCompactResponses': True}

Full appium server debug log

Environment

  • Appium version (or git revision) that exhibits the issue: 1.20.2
  • Last Appium version that did not exhibit the issue (if applicable):
  • Desktop OS/version used to run Appium: Manjaro 20.2.1 Nibia, x86_64 Linux 5.10.7-3-MANJARO
  • Node.js version (unless using Appium.app|exe): v14.8.0
  • Npm or Yarn package manager: npm 7.5.6
  • Mobile platform/version under test: Android 6.0.1
  • Real device or emulator/simulator: Real device
  • Appium CLI or Appium.app|exe: Appium CLI

It does start on the remote device, but is not exposed to a local port (e.g. port forwarding does not happen):

  async allocateMjpegServerPort () {
    if (this.opts.mjpegServerPort) {
      await this.adb.forwardPort(this.opts.mjpegServerPort, MJPEG_SERVER_DEVICE_PORT);
    }
  }

According to documentation GitHub - appium/appium-uiautomator2-driver: Appium driver for Android UIAutomator2, capability appium:mjpegServerPort is the number of the port UiAutomator2 server starts the MJPEG server on.
If I set capability mjpegServerPort to a custom port 12345, the UiAutomator2 mjpeg server still starts on port 7810. How can I set a custom port?

The documentation is probably not very clear there. The idea is to consume the stream from localhost. That is why mjpegServerPort capability does the port forwarding. Which means you should not change any settings, it is just enough to set a valid value to the capability above and start consuming the stream from http://localhost:$mjpegServerPort