브릿지(BritGi – Smart CCTV) 릴리즈

사용하지 않는 스마트폰을 CCTV로 활용할 수 있는 앱

브릿지(BritGi) V1.0

브릿지(BritGi)는 오래되서 사용하지 않는 스마트폰을 CCTV로 활용할 수 있는 앱입니다. 집을 비울때 반려견, 반려묘가 무었을 하고 있는지 내 스마트폰으로 실시간 조회 할 수 있습니다.

다운로드

아래 링크에서 무료로 다운로드 할 수 있습니다. 인앱결재 없이 계속 무료로 사용할 수 있습니다. 아이패드, 안드로이드 패드 지원합니다.

사용방법

브릿지(BritGi)는 오래된 스마트폰을 카메라로 사용하고 현재 쓰고 있는 스마트폰을 조회용으로 사용합니다.

  1. 카메라로 사용할 오래된 스마트폰과 지금쓰고 있는 스마트폰에 앱을 다운로드 하여 설치 합니다.
  2. 두개의 스마트폰에서 동일한 아이디(구글로그인 또는 애플로그인)로 로그인 합니다. (주의) 반드시 동일한 아이디로 로그인 해야 합니다. 카메라폰과 뷰어폰은 다른 종류라도 됩니다. – 예를들면 카메라는 안드로이드 뷰어는 아이폰
  3. 카메라 폰에서 카메라버튼을 눌러 카메라를 실행하고 뷰어폰에서 새로고침을 실행하면 카메라 목록이 화면에 나타나고 목록을 누르면 원격 영상을 볼수 있습니다.
  4. 카메라에 상시전원을 연결하고 고정하여 원격에서 전면, 후면 카메라를 선택하며 360도 거의 모든 방향을 볼 수 있습니다.

WebRTC(Peer-to-Peer)

브릿지(BritGi)는 카메라와 뷰어를 직접 연결하는 방식(WebRTC – Peer to Peer)으로 서버를 거치지 않고 영상정보를 전송합니다. 그래서 서버에 영상이 저장되지 않고 실시간으로만 조회가 가능합니다.

HD / Wifi, LTE, 5G

  • Wifi 연결에서는 HD 화질을 30 frame / sec 로 연결됩니다.
  • 5G/LTE 환경에서는 SD화질로 연결됩니다.
  • 가급적 Wifi 환경에서 사용하세요.

WebRTC, MQTT, Flutter

WebRTC를 이용한 화상/데이터 통신은 기본적으로 시그널 서버가 필요하다. 일반적으로 Websocket을 많이 사용하는데 서버는 클라이언트에서 전송되는 SDP, Candidate를 릴레이 하여 클라이언트가 연결할 상대방의 IP와 Port 정보를 주고 받은 다음 받은 정보를 이용하여 P2p 접속을 시도한다.

MQTT

MQTT는 발행/구독 기반으로 일대일, 일대다 데이터 통신에 적합하고 구독 채널을 트리구조로 구성 할 수 있기 때문에 Websocket에서 채팅방-서브 채팅방을 구현하는 기능을 아주 간단하게 구현 할 수 있다.

아이디어 – Mosquitto

WebRTC 화상통신앱을 만들며 처음부터 이 생각을 했다. WebSocket으로 채팅방을 만들지 않고 MQTT를 이용하면 안될까? Mosquitto 서버라면 보안성 문제도 쉽게 해결 할 수 있고 성능도 우수한 시그널 서버로 활용할 수 있지 않을까? 그래서 한번 해봤다.

Sample Code – Flutter

이 이미지는 대체 속성이 비어있습니다. 그 파일 이름은 1638688086230-1.jpg입니다

아래 링크의 소스 코드는 현재 만들고 있는 CCTV관련앱에서 기본적인 기능만 추출해서 Sample Project를 만들었다. Flutter로 만들어진 오픈소스이며 오픈된 Mosquitto 서버에 접속하여 동일한 토픽을 발행/구독하여 시그널을 주고 받은후 P2p를 연결하여 화상통신을 실행한다.

결론적으로 이 프로젝트에서 WebRTC 통신을 하기 위한 시그널 서버는 만들지않았다.

소스다운로드 링크

https://github.com/bipark/webrtc_mqtt_flutter_phone

P2p연결을 위해 Google Stun 서버를 사용하며 3G, LTE에서 연결이 되지 않을수도 있다. Stun 서버를 통한 P2p 연결이 불가능한 경우는 Turn 서버를 개별적으로 설치하고 운영해야 하는데 오픈소스인 Coturn을 활용하여 운용이 가능하다.

class MQTTManager {
  MqttServerClient? _client;

  MQTTManager(String clientId) {
    _client = MqttServerClient("test.mosquitto.org", clientId);
    _client!.autoReconnect = true;
    _client!.logging(on: false);
    _client!.keepAlivePeriod = 20;
  }

  Future<void> connect(String topic) async {
    try {
      await _client!.connect();
    } on Exception catch (e) {
      print('EXAMPLE::client exception - $e');
    }
    _client!.subscribe(topic, MqttQos.atMostOnce);
  }

  void publishMessage(String topic ,String message) {
    try {
      final builder1 = MqttClientPayloadBuilder();
      builder1.addString(message);
      _client!.publishMessage(topic, MqttQos.atLeastOnce, builder1.payload!);
    } on Exception catch (e) {
      print('EXAMPLE::client exception - $e');
    }
  }

  void subscribeTopic(String topic) {
    _client!.subscribe(topic, MqttQos.atMostOnce);
  }

  void unSubscribeTopic(String topic) {
    _client!.unsubscribe(topic);
  }

  void disconnect() {
    _client!.disconnect();
  }

  get client => _client;
}

WebRTC와 관련한 코드는 시그널 기능에 따른 많은 코드들이 요구되지만 셈플에서는 가장 기본적인 통신 기능만을 구현 했다.

  _mqtt = MQTTManager(_clientId);
  await _mqtt!.connect(_topic);
  
  ...
  var desc = await _localPc!.createOffer(offerSdpConstraints);
  await _localPc!.setLocalDescription(desc);
  _sendData("offer", desc.sdp);
  
  ...
  void _sendData(event, data) {
    var request = Map();
    request["command"] = "signal";
    request["clientid"] = _clientId;
    request["type"] = event;
    request["data"] = data;
    _mqtt!.publishMessage(_topic, jsonEncode(request).toString());
  }

박병일, 2021.12.5, rtlink.park@gmail.com