Versions Compared

Key

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

...

  • разрешение (ширина, высота)
  • скорость передачи (bitrate)
  • FPS (Frames Per Second) - для публикуемого видео
  • quality - для проигрываемого видео

Поток может быть опубикован опубликован как с аудио и видео, так и без аудио или видео (переключатели 'Send Audio' и 'Send Video').

Аудио и видео в публикуемом потоке могут быть выключены/включены соответствующими переключателями 'Mute Audio' и 'Mute Video' во время или до начала публикации.

Видео потоки могут воспроизводиться с видео или без видео (переключатель 'Play Video').

При необходимости, определенные кодеки можно исключить из публикации или воспроизведения (поле 'Strip codecs')

На скриншоте ниже представлен пример во время публикации потока.
В URL в поле ввода demo.flashphoner.com - адрес WCS-сервера.
Слева отображается видео с камеры, справа воспроизводится опубликованный поток.

Image RemovedImage Added
Вид с контролами для настроек настройками публикации показывается при нажатии на кнопку 'Local settings'

Image RemovedImage Added

а вид с контролами для настроек настройками воспроизведения - при нажатии на кнопку 'Remote settings'.

Image RemovedImage Added

Работа с кодом примера

Для разбора кода возьмем версию примера MediaDevices Swift, которая доступна для скачивания на GitHub.

Классы видов

  • класс для основного вида приложения: ViewController (файл имплементации ViewController.swift)
  • класс для вида с настройками публикации: LocalViewController (файл имплементации LocalViewController.swift)
  • класс для вида с настройками воспроизведения: RemoteViewController (файл имплементации RemoteViewController.swift)

1. Импорт API.

code

Code Block
languagejs
themeRDark
import FPWCSApi2Swift

2. Получение списка доступных медиа-устройств.

WCSApi2.getMediaDevices code

Code Block
languagecpp
themeRDark
localDevices = WCSApi2.getMediaDevices()

...

FPWCSApi2MediaDeviceList.audio FPWCSApi2MediaDeviceList.video code

Code Block
languagecpp
themeRDark
        if (localDevices?.audio?.count ?? 0 > 0) {
            microphone.text = (localDevices?.audio[0] as AnyObject).label
        }
        if (localDevices?.video?.count ?? 0 > 0) {
            camera.text = (localDevices?.video[0] as AnyObject).label
        }

4. Определение параметров аудио и видео для публикуемого потока.

FPWCSApi2VideoConstraints, FPWCSApi2AudioConstraints , FPWCSApi2AudioConstraints  code

Code Block
languagecpp
themeRDark
    func toMediaConstraints() -> FPWCSApi2MediaConstraints {
        let ret = FPWCSApi2MediaConstraints()
        if (self.audioSend.isOn) {
            let audio = FPWCSApi2AudioConstraints()
            audio.useFEC = audioFEC.isOn
            audio.useStereo = audioStereo.isOn
            audio.bitrate = Int(audioBitrate.text ?? "0") ?? 0
            ret.audio = audio
        }
        if (self.videoSend.isOn) {
            let video = FPWCSApi2VideoConstraints()
            for device in localDevices!.video {
                if ((device as AnyObject).label == camera.text) {
                    video.deviceID = (device as AnyObject).deviceID;
                }
            }
            video.minWidth = Int(videoWidth.text ?? "0") ?? 0
            video.maxWidth = video.minWidth
            video.minHeight = Int(videoHeight.text ?? "0") ?? 0
            video.maxHeight = video.minHeight
            video.minFrameRate = Int(videoFPS.text ?? "0") ?? 0
            video.maxFrameRate = video.minFrameRate
            video.bitrate = Int(videoBitrate.text ?? "0") ?? 0
            ret.video = video;
        }
        return ret;
    }

5. Определение параметров для проигрываемого потока.

FPWCSApi2AudioConstraintsFPWCSApi2VideoConstraints, FPWCSApi2AudioConstraints  FPWCSApi2AudioConstraints  code

Code Block
languagecpp
themeRDark
    func toMediaConstraints() -> FPWCSApi2MediaConstraints {
        let ret = FPWCSApi2MediaConstraints();
        ret.audio = FPWCSApi2AudioConstraints();
        if (playVideo.isOn) {
            let video = FPWCSApi2VideoConstraints();
            video.minWidth = Int(videoWidth.text ?? "0") ?? 0
            video.maxWidth = video.minWidth
            video.minHeight = Int(videoHeight.text ?? "0") ?? 0
            video.maxHeight = video.minWidth
            video.bitrate = Int(videoBitrate.text ?? "0") ?? 0
            video.quality = Int(videoQuality.text ?? "0") ?? 0
            ret.video = video;
        }
        return ret;
    }

6. Локальное тестирование микрофона и камеры

WCSApi2.getMediaAccess  code

Code Block
languagecpp
themeRDark
    @IBAction func testPressed(_ sender: Any) {
        if (testButton.title(for: .normal) == "TEST") {
            let constraints = FPWCSApi2MediaConstraints(audio: true, video: true)!
            do {
                try WCSApi2.getMediaAccess(constraints, localDisplay.videoView)
            } catch {
                print(error)
            }
            testButton.setTitle("RELEASE", for: .normal)
        } else {
            WCSApi2.releaseLocalMedia(display: localDisplay.videoView);
            testButton.setTitle("TEST", for: .normal)
        }
    }

...

WCSSession, WCSSession.connect  code

В параметрах сессии указываются:

...

WCSSession.createStream, WCSStream.publish  code

Методу createStream передаются параметры:

  • options.name - имя публикуемого потока
  • options.display - вид для локального отображения
  • options.constraints - параметры аудио и видео
  • options.stripCodecs - массив кодеков, которые должны быть исключены из SDP при публикации
  • options.transport - используемый WebRTC транспорт
Code Block
languagecpp
themeRDark
    @IBAction func publishPressed(_ sender: Any) {
        changeViewState(publishButton,false)
        if (publishButton.title(for: .normal) == "PUBLISH") {
            let options = FPWCSApi2StreamOptions()
            options.name = publishName.text
            options.display = localDisplay.videoView
            options.constraints = localMediaConstrains;
            do {
  options.stripCodecs = localStripCodecs?.split(separator: ",")
             options.transport = tcpTransport.isOn ? kFPWCSTransport.fpwcsTransportTCP : kFPWCSTransport.fpwcsTransportUDP;
            do {
                try publishStream = session!.createStream(options)
            } catch {
                print(error);
            }
            ...
            do {
                try publishStream?.publish()
            } catch {
                print(error);
            }
        }        
    }

...

WCSSession.createStream, WCSStream.play  code

Методу createStream передаются параметры:

  • options.name - имя воспроизводимого публикуемого потока
  • вид options.display - вид для локального отображения потока
  • options.constraints - параметры видео и аудиоаудио и видео
  • options.stripCodecs - массив кодеков, которые должны быть исключены из SDP при публикации
  • options.transport - используемый WebRTC транспорт
Code Block
languagecpp
themeRDark
    @IBAction func playPressed(_ sender: Any) {
        changeViewState(playButton,false)
        if (playButton.title(for: .normal) == "PLAY") {
            let options = FPWCSApi2StreamOptions()
            options.name = playName.text;
            options.display = remoteDisplay.videoView;
            options.constraints = remoteMediaConstrains;
            options.stripCodecs = remoteStripCodecs?.split(separator: ",")
            options.transport = tcpTransport.isOn ? kFPWCSTransport.fpwcsTransportTCP : kFPWCSTransport.fpwcsTransportUDP;
            do {
            playStream = try session!.createStream(options)
            } catch {
                print(error);
            }
            ...
            do {
                try playStream?.play()
            } catch {
                print(error);
            }
        }
    }

...