virtual int GetHeight(void) = 0;
virtual void Start(void) = 0;
virtual void Stop(void) = 0;
+ virtual int Push(void *obj) = 0;
virtual void SetStateCallback(StateCallback cb, void *user_data) = 0;
// Subscriber ONLY
AITT_STREAM_STATE_INIT = 0,
AITT_STREAM_STATE_READY = 1,
AITT_STREAM_STATE_PLAYING = 2,
+ AITT_STREAM_STATE_UNDERFLOW = 3,
+ AITT_STREAM_STATE_OVERFLOW = 4
};
+
enum AittStreamRole {
AITT_STREAM_ROLE_PUBLISHER = 0, // Role of source media
AITT_STREAM_ROLE_SUBSCRIBER = 1, // Role of destination(receiver)
}
}
+int Module::Push(void *obj)
+{
+ return AITT_ERROR_NOT_SUPPORTED;
+}
+
void Module::UpdateDiscoveryMsg()
{
if (role_ == AittStreamRole::AITT_STREAM_ROLE_SUBSCRIBER)
int GetHeight(void) override;
void Start(void) override;
void Stop(void) override;
+ int Push(void *obj) override;
void SetStateCallback(StateCallback cb, void *user_data) override;
void SetReceiveCallback(ReceiveCallback cb, void *user_data) override;
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
pkg_check_modules(AITT_WEBRTC_NEEDS REQUIRED
- capi-media-camera
capi-media-webrtc
gstreamer-video-1.0
json-glib-1.0
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "CameraHandler.h"
-
-#include "aitt_internal.h"
-
-#define RETURN_DEFINED_NAME_AS_STRING(defined_constant) \
- case defined_constant: \
- return #defined_constant;
-
-CameraHandler::~CameraHandler(void)
-{
- if (handle_) {
- camera_state_e state = CAMERA_STATE_NONE;
-
- int ret = camera_get_state(handle_, &state);
- if (ret != CAMERA_ERROR_NONE) {
- ERR("camera_get_state() Fail(%s)", ErrorToString(ret));
- }
-
- if (state == CAMERA_STATE_PREVIEW) {
- INFO("CameraHandler preview is not stopped (stop)");
- ret = camera_stop_preview(handle_);
- if (ret != CAMERA_ERROR_NONE) {
- ERR("camera_stop_preview() Fail(%s)", ErrorToString(ret));
- }
- }
- }
-
- if (handle_)
- camera_destroy(handle_);
-}
-
-int CameraHandler::Init(const MediaPacketPreviewCallback &preview_cb, void *user_data)
-{
- int ret = camera_create(CAMERA_DEVICE_CAMERA0, &handle_);
- if (ret != CAMERA_ERROR_NONE) {
- ERR("camera_create() Fail(%s)", ErrorToString(ret));
- return -1;
- }
- SettingCamera(preview_cb, user_data);
-
- return 0;
-}
-
-void CameraHandler::SettingCamera(const MediaPacketPreviewCallback &preview_cb, void *user_data)
-{
- int ret = camera_set_media_packet_preview_cb(handle_, CameraPreviewCB, this);
- if (ret != CAMERA_ERROR_NONE) {
- ERR("camera_set_media_packet_preview_cb() Fail(%s)", ErrorToString(ret));
- return;
- }
- media_packet_preview_cb_ = preview_cb;
- user_data_ = user_data;
-}
-
-void CameraHandler::Deinit(void)
-{
- if (!handle_) {
- ERR("Handler is nullptr");
- return;
- }
-
- is_started_ = false;
- media_packet_preview_cb_ = nullptr;
- user_data_ = nullptr;
-}
-
-int CameraHandler::StartPreview(void)
-{
- camera_state_e state;
- int ret = camera_get_state(handle_, &state);
- if (ret != CAMERA_ERROR_NONE) {
- ERR("camera_get_state() Fail(%s)", ErrorToString(ret));
- return -1;
- }
-
- if (state == CAMERA_STATE_PREVIEW) {
- INFO("Preview is already started");
- is_started_ = true;
- return 0;
- }
-
- ret = camera_start_preview(handle_);
- if (ret != CAMERA_ERROR_NONE) {
- ERR("camera_start_preview() Fail(%s)", ErrorToString(ret));
- return -1;
- }
-
- is_started_ = true;
-
- return 0;
-}
-
-int CameraHandler::StopPreview(void)
-{
- RETV_IF(handle_ == nullptr, -1);
- is_started_ = false;
-
- return 0;
-}
-
-void CameraHandler::CameraPreviewCB(media_packet_h media_packet, void *user_data)
-{
- auto camera_handler = static_cast<CameraHandler *>(user_data);
- if (!camera_handler) {
- ERR("Invalid user_data");
- return;
- }
-
- if (!camera_handler->is_started_) {
- ERR("Preveiw is not started yet");
- return;
- }
-
- if (!camera_handler->media_packet_preview_cb_) {
- ERR("Preveiw cb is not set");
- return;
- }
-
- camera_handler->media_packet_preview_cb_(media_packet, camera_handler->user_data_);
-}
-
-const char *CameraHandler::ErrorToString(const int error)
-{
- switch (error) {
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_NONE)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_INVALID_PARAMETER)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_INVALID_STATE)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_OUT_OF_MEMORY)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_DEVICE)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_INVALID_OPERATION)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_SECURITY_RESTRICTED)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_DEVICE_BUSY)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_DEVICE_NOT_FOUND)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_ESD)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_PERMISSION_DENIED)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_NOT_SUPPORTED)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_RESOURCE_CONFLICT)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_ERROR_SERVICE_DISCONNECTED)
- }
-
- return "Unknown error";
-}
-
-const char *CameraHandler::StateToString(const camera_state_e state)
-{
- switch (state) {
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_STATE_NONE)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_STATE_CREATED)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_STATE_PREVIEW)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_STATE_CAPTURING)
- RETURN_DEFINED_NAME_AS_STRING(CAMERA_STATE_CAPTURED)
- }
-
- return "Unknown state";
-}
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <camera.h>
-
-#include <functional>
-
-class CameraHandler {
- public:
- using MediaPacketPreviewCallback = std::function<void(media_packet_h, void *)>;
-
- ~CameraHandler();
- int Init(const MediaPacketPreviewCallback &preview_cb, void *user_data);
- void Deinit(void);
- int StartPreview(void);
- int StopPreview(void);
-
- static const char *ErrorToString(const int error);
- static const char *StateToString(const camera_state_e state);
-
- private:
- void SettingCamera(const MediaPacketPreviewCallback &preview_cb, void *user_data);
- static void CameraPreviewCB(media_packet_h media_packet, void *user_data);
-
- camera_h handle_;
- bool is_started_;
- MediaPacketPreviewCallback media_packet_preview_cb_;
- void *user_data_;
-};
discovery_cb_ = discovery_.AddDiscoveryCB(stream_manager_->GetWatchingTopic(),
std::bind(&Module::DiscoveryMessageCallback, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
+ stream_manager_->SetIceCandidateAddedCallback(std::bind(&Module::OnIceCandidateAdded, this));
+ stream_manager_->SetStreamStartCallback(std::bind(&Module::OnStreamStarted, this));
+ stream_manager_->SetStreamStopCallback(std::bind(&Module::OnStreamStopped, this));
+ stream_manager_->SetStreamStateCallback(
+ std::bind(&Module::OnStreamState, this, std::placeholders::_1));
}
Module::~Module(void)
stream_manager_->SetHeight(std::stoi(value));
else if (key == "FRAME_RATE")
stream_manager_->SetFrameRate(std::stoi(value));
+ else if (key == "MEDIA_FORMAT")
+ stream_manager_->SetMediaFormat(value);
+ else if (key == "SOURCE_TYPE")
+ stream_manager_->SetSourceType(value);
+ else if (key == "DECODE_CODEC")
+ stream_manager_->SetDecodeCodec(value);
else
return AITT_ERROR_INVALID_PARAMETER;
} catch (std::exception &e) {
void Module::Start(void)
{
- stream_manager_->SetIceCandidateAddedCallback(std::bind(&Module::OnIceCandidateAdded, this));
- stream_manager_->SetStreamStartCallback(std::bind(&Module::OnStreamStarted, this));
- stream_manager_->SetStreamStopCallback(std::bind(&Module::OnStreamStopped, this));
-
stream_manager_->Start();
}
{
}
+int Module::Push(void *obj)
+{
+ // TODO: We need to classify error codes
+ return stream_manager_->Push(obj);
+}
+
void Module::OnIceCandidateAdded(void)
{
DBG("OnIceCandidateAdded");
discovery_.UpdateDiscoveryMsg(stream_manager_->GetTopic(), msg.data(), msg.size());
}
+void Module::OnStreamState(const std::string &state)
+{
+ if (!state_callback_)
+ return;
+
+ DBG("%s", state.c_str());
+ if (state == "IDLE")
+ state_callback_(this, AITT_STREAM_STATE_INIT, state_cb_user_data_);
+ else if (state == "PLAYING")
+ state_callback_(this, AITT_STREAM_STATE_PLAYING, state_cb_user_data_);
+ else if (state == "UNDERFLOW")
+ state_callback_(this, AITT_STREAM_STATE_UNDERFLOW, state_cb_user_data_);
+ else if (state == "OVERFLOW")
+ state_callback_(this, AITT_STREAM_STATE_OVERFLOW, state_cb_user_data_);
+}
+
void Module::SetStateCallback(StateCallback cb, void *user_data)
{
state_callback_ = cb;
int GetHeight(void) override;
void Start(void) override;
void Stop(void) override;
+ int Push(void *obj) override;
void SetStateCallback(StateCallback cb, void *user_data) override;
void SetReceiveCallback(ReceiveCallback cb, void *user_data) override;
void OnIceCandidateAdded(void);
void OnStreamStarted(void);
void OnStreamStopped(void);
+ void OnStreamState(const std::string &state);
void DiscoveryMessageCallback(const std::string &clientId, const std::string &status,
const void *msg, const int szmsg);
video_appsrc_(nullptr),
decode_pipeline_(nullptr)
{
+ SetWebRtcStreamCallbacks(stream_);
+ stream_.AttachSignals(false, need_display_);
+ stream_.ActivateSource();
+ stream_.SetDecodeCodec(decode_codec_);
}
SinkStreamManager::~SinkStreamManager()
void SinkStreamManager::OnStreamStateChanged(WebRtcState::Stream state, WebRtcStream &stream)
{
DBG("OnSinkStreamStateChanged: %s", WebRtcState::StreamToStr(state).c_str());
+ if (stream_state_cb_)
+ stream_state_cb_(WebRtcState::StreamToStr(state));
if (state == WebRtcState::Stream::NEGOTIATING) {
stream.CreateOfferAsync(std::bind(&SinkStreamManager::OnOfferCreated, this,
std::placeholders::_1, std::ref(stream)));
GstElement *src = gst_element_factory_make("appsrc", nullptr);
// TODO:How do we can know decoder type
- GstCaps *app_src_caps = gst_caps_new_simple("video/x-vp8", nullptr, nullptr);
- g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME, "caps", app_src_caps, nullptr);
- gst_caps_unref(app_src_caps);
+ GstElement *dec = nullptr;
+ if (decode_codec_ == "H264") {
+ GstCaps *app_src_caps = gst_caps_new_simple("video/x-h264", "stream-format", G_TYPE_STRING,
+ "byte-stream", "alignment", G_TYPE_STRING, "au", NULL);
+
+ g_object_set(G_OBJECT(src), "caps", app_src_caps, "format", GST_FORMAT_TIME, NULL);
+ gst_caps_unref(app_src_caps);
- GstElement *dec = gst_element_factory_make("vp8dec", nullptr);
+ dec = gst_element_factory_make("avdec_h264", NULL);
+ } else {
+ GstCaps *app_src_caps = gst_caps_new_simple("video/x-vp8", nullptr, nullptr);
+ g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME, "caps", app_src_caps, nullptr);
+ gst_caps_unref(app_src_caps);
+
+ dec = gst_element_factory_make("vp8dec", nullptr);
+ }
GstElement *convert = gst_element_factory_make("videoconvert", nullptr);
GstElement *filter = gst_element_factory_make("capsfilter", "I420toRGBCapsfilter");
GstCaps *filter_caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "BGR", NULL);
return;
}
RET_IF(vinfo.width == 0 || vinfo.height == 0 || vinfo.finfo == nullptr);
- manager->SetFormat(vinfo.finfo->name, vinfo.width, vinfo.height);
+ manager->SetMediaFormat(vinfo.finfo->name);
+ manager->SetWidth(vinfo.width);
+ manager->SetHeight(vinfo.height);
manager->HandleFrame(buffer);
}
void SinkStreamManager::AddStream(const std::string &discovery_id)
{
- SetWebRtcStreamCallbacks(stream_);
- stream_.Create(false, need_display_);
stream_.Start();
std::stringstream s_stream;
request_server_.SetOnFrameCallback(cb);
}
+int SinkStreamManager::Push(void *obj)
+{
+ DBG("Not supported");
+ return -1;
+}
+
} // namespace AittWebRTCNamespace
#include <mutex>
#include <thread>
-#include "StreamManager.h"
#include "RequestServer.h"
+#include "StreamManager.h"
namespace AittWebRTCNamespace {
class SinkStreamManager : public StreamManager {
virtual ~SinkStreamManager();
std::vector<uint8_t> GetDiscoveryMessage(void) override;
void SetOnFrameCallback(OnFrameCallback cb) override;
+ int Push(void *obj) override;
private:
void SetWebRtcStreamCallbacks(WebRtcStream &stream) override;
const std::string &thread_id)
: StreamManager(topic + "/SRC", topic + "/SINK", aitt_id, thread_id)
{
+ SetWebRtcStreamCallbacks(stream_);
+ stream_.AttachSignals(true, false);
+ source_type_ = "CAMERA";
+ stream_.SetSourceType(WEBRTC_MEDIA_SOURCE_TYPE_CAMERA);
+ stream_.ActivateSource();
}
SrcStreamManager::~SrcStreamManager()
stream.GetEventHandler().SetOnIceCandidateCb(
std::bind(&SrcStreamManager::OnIceCandidate, this));
+
+ stream.GetEventHandler().SetOnSourceBufferStateCb(
+ std::bind(&SrcStreamManager::OnSourceBufferStateNotify, this, std::placeholders::_1));
}
void SrcStreamManager::OnStreamStateChanged(WebRtcState::Stream state)
{
DBG("OnSrcStreamStateChanged: %s", WebRtcState::StreamToStr(state).c_str());
+ if (stream_state_cb_)
+ stream_state_cb_(WebRtcState::StreamToStr(state));
}
void SrcStreamManager::OnSignalingStateNotify(WebRtcState::Signaling state, WebRtcStream &stream)
ice_candidate_added_cb_();
}
+void SrcStreamManager::OnSourceBufferStateNotify(WebRtcState::SourceBufferState state)
+{
+ DBG("OnSourceBufferStateNotify: %s", WebRtcState::SourceBufferStateToStr(state).c_str());
+ if (stream_state_cb_)
+ stream_state_cb_(WebRtcState::SourceBufferStateToStr(state));
+}
+
void SrcStreamManager::HandleStreamState(const std::string &discovery_id,
const std::vector<uint8_t> &message)
{
void SrcStreamManager::AddStream(const std::string &discovery_id, const std::string &id,
const std::string &sdp, const std::vector<std::string> &ice_candidates)
{
- SetWebRtcStreamCallbacks(stream_);
- CreateSrcStream();
stream_.Start();
std::stringstream s_stream;
return;
}
-void SrcStreamManager::CreateSrcStream(void)
-{
- SetWebRtcStreamCallbacks(stream_);
- stream_.Create(true, false);
- if (source_type_ == "MEDIA_PACKET")
- stream_.AttachMediaPacketSource();
- else if (source_type_ == "CAMERA") {
- stream_.AttachCameraSource();
- if (width_ && height_)
- stream_.SetVideoResolution(width_, height_);
- if (frame_rate_)
- stream_.SetVideoFrameRate(frame_rate_);
- } else
- DBG("Source is not available");
-}
-
std::vector<uint8_t> SrcStreamManager::GetDiscoveryMessage(void)
{
std::vector<uint8_t> message;
return message;
}
+int SrcStreamManager::Push(void *obj)
+{
+ if (source_type_ != "MEDIA_PACKET") {
+ DBG("Wrong source type");
+ return -1;
+ }
+
+ return stream_.Push(obj);
+}
+
} // namespace AittWebRTCNamespace
const std::string &thread_id);
virtual ~SrcStreamManager();
std::vector<uint8_t> GetDiscoveryMessage(void) override;
+ int Push(void *obj) override;
private:
void SetWebRtcStreamCallbacks(WebRtcStream &stream) override;
void OnAnswerCreated(std::string sdp, WebRtcStream &stream);
void OnIceCandidate(void);
void OnSignalingStateNotify(WebRtcState::Signaling state, WebRtcStream &stream);
+ void OnSourceBufferStateNotify(WebRtcState::SourceBufferState state);
void HandleStreamState(const std::string &discovery_id,
const std::vector<uint8_t> &message) override;
void HandleStreamInfo(const std::string &discovery_id,
width_(0),
height_(0),
frame_rate_(0),
- source_type_("CAMERA"),
+ //Need to sync with source_type_ on stream
+ source_type_("NULL"),
+ decode_codec_("VP8"),
topic_(topic),
watching_topic_(watching_topic),
aitt_id_(aitt_id),
thread_id_(thread_id)
{
+ stream_.AddDataChannel();
}
bool StreamManager::IsStarted(void) const
return height_;
}
-void StreamManager::SetFormat(const std::string &format, int width, int height)
-{
- format_ = format;
- width_ = width;
- height_ = height;
-}
-
void StreamManager::SetWidth(int width)
{
+ if (width_ == width)
+ return;
+
+ if (source_type_ == "MEDIA_PACKET" && height_ && frame_rate_ && format_.size())
+ stream_.SetMediaFormat(width_, height_, frame_rate_, format_);
+ else if (source_type_ == "CAMERA" && height_)
+ stream_.SetVideoResolution(width, height_);
width_ = width;
}
void StreamManager::SetHeight(int height)
{
+ if (height_ == height)
+ return;
+
+ if (source_type_ == "MEDIA_PACKET" && width_ && frame_rate_ && format_.size())
+ stream_.SetMediaFormat(width_, height, frame_rate_, format_);
+ else if (source_type_ == "CAMERA" && width_)
+ stream_.SetVideoResolution(width_, height);
height_ = height;
}
void StreamManager::SetFrameRate(int frame_rate)
{
+ if (frame_rate_ == frame_rate)
+ return;
+
+ if (source_type_ == "MEDIA_PACKET" && width_ && height_ && format_.size())
+ stream_.SetMediaFormat(width_, height_, frame_rate, format_);
+ else if (source_type_ == "CAMERA")
+ stream_.SetVideoFrameRate(frame_rate);
frame_rate_ = frame_rate;
}
void StreamManager::SetSourceType(const std::string &source_type)
{
+ if (source_type_ == source_type)
+ return;
+
+ stream_.DeactivateSource();
+ if (source_type == "MEDIA_PACKET") {
+ stream_.SetSourceType(WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET);
+ stream_.ActivateSource();
+ if (width_ && height_ && frame_rate_ && format_.size())
+ stream_.SetMediaFormat(width_, height_, frame_rate_, format_);
+ } else if (source_type == "CAMERA") {
+ stream_.SetSourceType(WEBRTC_MEDIA_SOURCE_TYPE_CAMERA);
+ stream_.ActivateSource();
+ if (width_ && height_)
+ stream_.SetVideoResolution(width_, height_);
+ if (frame_rate_)
+ stream_.SetVideoFrameRate(frame_rate_);
+ } else if (source_type == "NULL") {
+ stream_.SetSourceType(WEBRTC_MEDIA_SOURCE_TYPE_NULL);
+ stream_.ActivateSource();
+ } else
+ DBG("%s is not available source type", source_type.c_str());
+
source_type_ = source_type;
}
+void StreamManager::SetMediaFormat(const std::string &format)
+{
+ if (format_ == format)
+ return;
+
+ if (source_type_ == "MEDIA_PACKET" && width_ && height_ && frame_rate_)
+ stream_.SetMediaFormat(width_, height_, frame_rate_, format);
+ format_ = format;
+}
+
+void StreamManager::SetDecodeCodec(const std::string &codec)
+{
+ if (decode_codec_ == codec)
+ return;
+
+ if (source_type_ == "NULL")
+ stream_.SetDecodeCodec(codec);
+ decode_codec_ = codec;
+}
+
void StreamManager::Start(void)
{
DBG("%s %s", __func__, GetTopic().c_str());
stream_stop_cb_ = cb;
}
+void StreamManager::SetStreamStateCallback(StreamStateCallback cb)
+{
+ stream_state_cb_ = cb;
+}
+
void StreamManager::SetOnFrameCallback(OnFrameCallback cb)
{
on_frame_cb_ = cb;
using StreamStartCallback = std::function<void(void)>;
using StreamStopCallback = std::function<void(void)>;
using OnFrameCallback = std::function<void(void *)>;
+ using StreamStateCallback = std::function<void(const std::string &)>;
explicit StreamManager(const std::string &topic, const std::string &watching_topic,
const std::string &aitt_id, const std::string &thread_id);
virtual ~StreamManager() = default;
std::string GetFormat(void);
int GetWidth(void);
int GetHeight(void);
- void SetFormat(const std::string &format, int width, int height);
void SetWidth(int width);
void SetHeight(int height);
void SetFrameRate(int frame_rate);
+ void SetMediaFormat(const std::string &format);
void SetSourceType(const std::string &source_type);
+ void SetDecodeCodec(const std::string &codec);
void Start(void);
void Stop(void);
+ virtual int Push(void *obj) = 0;
void HandleRemovedClient(const std::string &discovery_id);
void HandleMsg(const std::string &discovery_id, const std::vector<uint8_t> &message);
void SetIceCandidateAddedCallback(IceCandidateAddedCallback cb);
void SetStreamStartCallback(StreamStartCallback cb);
void SetStreamStopCallback(StreamStopCallback cb);
+ void SetStreamStateCallback(StreamStateCallback cb);
virtual void SetOnFrameCallback(OnFrameCallback cb);
std::string GetTopic(void) const;
int frame_rate_;
std::string source_type_;
std::string format_;
+ std::string decode_codec_;
std::string topic_;
std::string watching_topic_;
// TODO: why dont' we remove below
std::string aitt_id_;
std::string thread_id_;
- // We assume Module class can't be copyable
std::string peer_aitt_id_;
+ // We assume Module class can't be copyable
WebRtcStream stream_;
StreamStartCallback stream_start_cb_;
StreamStopCallback stream_stop_cb_;
+ StreamStateCallback stream_state_cb_;
IceCandidateAddedCallback ice_candidate_added_cb_;
OnFrameCallback on_frame_cb_;
};
void UnsetTrackAddedCb(void) { on_track_added_cb_ = nullptr; };
+ void SetOnSourceBufferStateCb(std::function<void(WebRtcState::SourceBufferState)> on_source_buffer_state_notify_cb)
+ {
+ on_source_buffer_state_notify_cb_ = on_source_buffer_state_notify_cb;
+ }
+ void CallOnSourceBufferStateCb(WebRtcState::SourceBufferState state) const
+ {
+ if (on_source_buffer_state_notify_cb_)
+ on_source_buffer_state_notify_cb_(state);
+ };
+ void UnsetSourceBufferStateCb(void) { on_source_buffer_state_notify_cb_ = nullptr; };
+
private:
std::function<void(void)> on_negotiation_needed_cb_;
std::function<void(WebRtcState::Stream)> on_state_changed_cb_;
std::function<void(WebRtcState::IceConnection)> on_ice_connection_state_notify_cb_;
std::function<void(media_packet_h)> on_encoded_frame_cb_;
std::function<void(unsigned int id)> on_track_added_cb_;
+ std::function<void(WebRtcState::SourceBufferState)> on_source_buffer_state_notify_cb_;
};
} // namespace AittWebRTCNamespace
return std::string("");
}
+WebRtcState::SourceBufferState WebRtcState::ToSourceBufferState(webrtc_media_packet_source_buffer_state_e state)
+{
+ switch (state) {
+ case WEBRTC_MEDIA_PACKET_SOURCE_BUFFER_STATE_UNDERFLOW: {
+ return SourceBufferState::UNDERFLOW;
+ }
+ case WEBRTC_MEDIA_PACKET_SOURCE_BUFFER_STATE_OVERFLOW: {
+ return SourceBufferState::OVERFLOW;
+ }
+ }
+ return SourceBufferState::OVERFLOW;
+}
+
+std::string WebRtcState::SourceBufferStateToStr(WebRtcState::SourceBufferState state)
+{
+ switch (state) {
+ case (WebRtcState::SourceBufferState::UNDERFLOW): {
+ return std::string("UNDERFLOW");
+ }
+ case (WebRtcState::SourceBufferState::OVERFLOW): {
+ return std::string("OVERFLOW");
+ }
+ }
+ return std::string("");
+}
+
} // namespace AittWebRTCNamespace
CLOSED,
};
+ enum class SourceBufferState {
+ UNDERFLOW,
+ OVERFLOW,
+ };
+
public:
static Stream ToStreamState(webrtc_state_e state);
static std::string StreamToStr(WebRtcState::Stream state);
static std::string IceGatheringToStr(WebRtcState::IceGathering state);
static IceConnection ToIceConnectionState(webrtc_ice_connection_state_e state);
static std::string IceConnectionToStr(WebRtcState::IceConnection state);
+ static SourceBufferState ToSourceBufferState(webrtc_media_packet_source_buffer_state_e state);
+ static std::string SourceBufferStateToStr(WebRtcState::SourceBufferState state);
};
} // namespace AittWebRTCNamespace
#include "WebRtcStream.h"
#include <inttypes.h>
+#include <media_format.h>
#include <webrtc_internal.h>
+#include <stdexcept>
+
#include "WebRtcMessage.h"
#include "aitt_internal.h"
namespace AittWebRTCNamespace {
-WebRtcStream::WebRtcStream() : webrtc_handle_(nullptr), channel_(nullptr), source_id_(0)
+WebRtcStream::WebRtcStream()
+ : webrtc_handle_(nullptr),
+ source_type_(WEBRTC_MEDIA_SOURCE_TYPE_NULL),
+ channel_(nullptr),
+ source_id_(0)
{
+ // Notice for Tizen webrtc handle
+ // This API includes file read operation, launching thread,
+ // gstreamer library initialization, and so on.
+ auto ret = webrtc_create(&webrtc_handle_);
+ if (ret != WEBRTC_ERROR_NONE)
+ throw std::runtime_error("WebRtc Handler Creation Failed");
}
WebRtcStream::~WebRtcStream()
DBG("%s", __func__);
}
-bool WebRtcStream::Create(bool is_source, bool need_display)
-{
- if (webrtc_handle_) {
- ERR("Already created %p", webrtc_handle_);
- return false;
- }
-
- auto ret = webrtc_create(&webrtc_handle_);
- if (ret != WEBRTC_ERROR_NONE) {
- ERR("Failed to create webrtc handle");
- return false;
- }
-
- if (!is_source) {
- auto add_source_ret =
- webrtc_add_media_source(webrtc_handle_, WEBRTC_MEDIA_SOURCE_TYPE_NULL, &source_id_);
- if (add_source_ret != WEBRTC_ERROR_NONE)
- ERR("Failed to add media source");
- auto set_transceiver_codec_ret = webrtc_media_source_set_transceiver_codec(webrtc_handle_,
- source_id_, WEBRTC_MEDIA_TYPE_VIDEO, WEBRTC_TRANSCEIVER_CODEC_VP8);
- if (set_transceiver_codec_ret != WEBRTC_ERROR_NONE)
- ERR("Failed to set transceiver codec");
- }
-
- webrtc_create_data_channel(webrtc_handle_, "label", nullptr, &channel_);
- AttachSignals(is_source, need_display);
-
- return true;
-}
-
void WebRtcStream::Destroy(void)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return;
- }
auto stop_ret = webrtc_stop(webrtc_handle_);
if (stop_ret != WEBRTC_ERROR_NONE)
ERR("Failed to stop webrtc handle");
bool WebRtcStream::Start(void)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return false;
- }
-
auto ret = webrtc_start(webrtc_handle_);
if (ret != WEBRTC_ERROR_NONE)
ERR("Failed to start webrtc handle");
bool WebRtcStream::Stop(void)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return false;
- }
-
auto ret = webrtc_stop(webrtc_handle_);
if (ret != WEBRTC_ERROR_NONE)
ERR("Failed to stop webrtc handle");
return ret == WEBRTC_ERROR_NONE;
}
-bool WebRtcStream::AttachCameraSource(void)
+int WebRtcStream::Push(void *obj)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return false;
- }
-
- if (source_id_) {
- ERR("source already attached");
- return false;
- }
-
- auto ret =
- webrtc_add_media_source(webrtc_handle_, WEBRTC_MEDIA_SOURCE_TYPE_CAMERA, &source_id_);
+ auto ret = webrtc_media_packet_source_push_packet(webrtc_handle_, source_id_,
+ static_cast<media_packet_h>(obj));
if (ret != WEBRTC_ERROR_NONE)
- ERR("Failed to add media source");
+ ERR("Failed to push packet");
- return ret == WEBRTC_ERROR_NONE;
+ // TODO what should be initialized?
+ return ret;
}
-bool WebRtcStream::AttachMediaPacketSource(void)
+void WebRtcStream::SetSourceType(webrtc_media_source_type_e source_type)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return false;
- }
+ source_type_ = source_type;
+}
+bool WebRtcStream::ActivateSource(void)
+{
if (source_id_) {
ERR("source already attached");
return false;
}
- auto ret = webrtc_add_media_source(webrtc_handle_, WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET,
- &source_id_);
+ auto ret = webrtc_add_media_source(webrtc_handle_, source_type_, &source_id_);
if (ret != WEBRTC_ERROR_NONE)
ERR("Failed to add media source");
+ if (source_type_ == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET) {
+ int set_buffer_cb_ret = webrtc_media_packet_source_set_buffer_state_changed_cb(
+ webrtc_handle_, source_id_, OnBufferStateChanged, this);
+ DBG("webrtc_media_packet_source_set_buffer_state_changed_cb %s",
+ set_buffer_cb_ret == WEBRTC_ERROR_NONE ? "Succeeded" : "failed");
+ }
return ret == WEBRTC_ERROR_NONE;
}
-bool WebRtcStream::DetachSource(void)
+bool WebRtcStream::DeactivateSource(void)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return false;
- }
-
if (!source_id_) {
ERR("Media source is not attached");
return false;
auto ret = webrtc_remove_media_source(webrtc_handle_, source_id_);
if (ret != WEBRTC_ERROR_NONE)
ERR("Failed to remove media source");
+ else
+ source_id_ = 0;
return ret == WEBRTC_ERROR_NONE;
}
bool WebRtcStream::SetVideoResolution(int width, int height)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return false;
- }
-
if (!source_id_) {
ERR("Media source is not attached");
return false;
bool WebRtcStream::SetVideoFrameRate(int frame_rate)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return false;
- }
-
if (!source_id_) {
ERR("Media source is not attached");
return false;
return ret == WEBRTC_ERROR_NONE;
}
-bool WebRtcStream::CreateOfferAsync(std::function<void(std::string)> on_created_cb)
+bool WebRtcStream::SetMediaFormat(int width, int height, int frame_rate, const std::string &format)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
+ media_format_h media_format =
+ static_cast<media_format_h>(GetMediaFormatHandler(width, height, frame_rate, format));
+ if (!media_format)
return false;
- }
+
+ auto ret = webrtc_media_packet_source_set_format(webrtc_handle_, source_id_, media_format);
+ if (ret != WEBRTC_ERROR_NONE)
+ ERR("Failed to set media format");
+ media_format_unref(media_format);
+
+ return ret == WEBRTC_ERROR_NONE;
+}
+
+void WebRtcStream::SetDecodeCodec(const std::string &codec)
+{
+ webrtc_transceiver_codec_e transceiver_codec = WEBRTC_TRANSCEIVER_CODEC_VP8;
+ if (codec == "VP9")
+ transceiver_codec = WEBRTC_TRANSCEIVER_CODEC_VP9;
+ else if (codec == "H264")
+ transceiver_codec = WEBRTC_TRANSCEIVER_CODEC_H264;
+ auto ret = webrtc_media_source_set_transceiver_codec(webrtc_handle_, source_id_,
+ WEBRTC_MEDIA_TYPE_VIDEO, transceiver_codec);
+ if (ret != WEBRTC_ERROR_NONE)
+ ERR("Failed to set transceiver codec");
+
+ return;
+}
+
+bool WebRtcStream::CreateOfferAsync(std::function<void(std::string)> on_created_cb)
+{
on_offer_created_cb_ = on_created_cb;
auto ret = webrtc_create_offer_async(webrtc_handle_, NULL, OnOfferCreated, this);
if (ret != WEBRTC_ERROR_NONE)
bool WebRtcStream::CreateAnswerAsync(std::function<void(std::string)> on_created_cb)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return false;
- }
on_answer_created_cb_ = on_created_cb;
auto ret = webrtc_create_answer_async(webrtc_handle_, NULL, OnAnswerCreated, this);
if (ret != WEBRTC_ERROR_NONE)
bool WebRtcStream::SetLocalDescription(const std::string &description)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return false;
- }
-
auto ret = webrtc_set_local_description(webrtc_handle_, description.c_str());
if (ret != WEBRTC_ERROR_NONE)
ERR("Failed to set local description");
bool WebRtcStream::SetRemoteDescription(const std::string &description)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return false;
- }
-
auto ret = webrtc_set_remote_description(webrtc_handle_, description.c_str());
if (ret != WEBRTC_ERROR_NONE)
ERR("Failed to set remote description");
bool WebRtcStream::AddIceCandidateFromMessage(const std::string &ice_message)
{
- ERR("%s", __func__);
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return false;
- }
auto ret = webrtc_add_ice_candidate(webrtc_handle_, ice_message.c_str());
if (ret != WEBRTC_ERROR_NONE)
ERR("Failed to set add ice candidate");
DBG("webrtc_foreach_stats failed");
}
-void WebRtcStream::AttachSignals(bool is_source, bool need_display)
+void WebRtcStream::AddDataChannel(void)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return;
- }
+ webrtc_create_data_channel(webrtc_handle_, "label", nullptr, &channel_);
+}
+void WebRtcStream::AttachSignals(bool is_source, bool need_display)
+{
int ret = WEBRTC_ERROR_NONE;
// TODO: ADHOC TV profile doesn't show DBG level log
ret = webrtc_set_error_cb(webrtc_handle_, OnError, this);
void WebRtcStream::DetachSignals(void)
{
- if (!webrtc_handle_) {
- ERR("WebRTC handle is not created");
- return;
- }
-
webrtc_unset_error_cb(webrtc_handle_);
webrtc_unset_state_changed_cb(webrtc_handle_);
webrtc_unset_signaling_state_change_cb(webrtc_handle_);
ERR("%s", __func__);
}
+void WebRtcStream::OnBufferStateChanged(unsigned int id,
+ webrtc_media_packet_source_buffer_state_e state, void *user_data)
+{
+ ERR("%s", __func__);
+ auto webrtc_stream = static_cast<WebRtcStream *>(user_data);
+ RET_IF(webrtc_stream == nullptr);
+ webrtc_stream->GetEventHandler().CallOnSourceBufferStateCb(
+ WebRtcState::ToSourceBufferState(state));
+}
+
+static media_format_mimetype_e __get_video_format_enum(const std::string &format)
+{
+ if (format == "I420")
+ return MEDIA_FORMAT_I420;
+ else if (format == "NV12")
+ return MEDIA_FORMAT_NV12;
+ else if (format == "VP8")
+ return MEDIA_FORMAT_VP8;
+ else if (format == "VP9")
+ return MEDIA_FORMAT_VP9;
+ else if (format == "H264")
+ return MEDIA_FORMAT_H264_HP;
+ else if (format == "JPEG")
+ return MEDIA_FORMAT_MJPEG;
+ else
+ return MEDIA_FORMAT_MAX;
+}
+
+void *WebRtcStream::GetMediaFormatHandler(int width, int height, int frame_rate,
+ const std::string &format)
+{
+ media_format_h media_format = nullptr;
+ auto ret = media_format_create(&media_format);
+ if (ret != MEDIA_FORMAT_ERROR_NONE) {
+ DBG("failed to media_format_create()");
+ return nullptr;
+ }
+
+ ret = media_format_set_video_mime(media_format, __get_video_format_enum(format));
+ ret |= media_format_set_video_width(media_format, width);
+ ret |= media_format_set_video_height(media_format, height);
+ ret |= media_format_set_video_frame_rate(media_format, frame_rate);
+ if (ret != MEDIA_FORMAT_ERROR_NONE) {
+ DBG("failed to set video format");
+ media_format_unref(media_format);
+ return nullptr;
+ }
+
+ return media_format;
+}
} // namespace AittWebRTCNamespace
public:
WebRtcStream();
~WebRtcStream();
- bool Create(bool is_source, bool need_display);
void Destroy(void);
bool Start(void);
bool Stop(void);
- bool AttachCameraSource(void);
- bool AttachMediaPacketSource(void);
- bool DetachSource(void);
+ int Push(void *obj);
+ void SetSourceType(webrtc_media_source_type_e source_type);
+ bool ActivateSource(void);
+ bool DeactivateSource(void);
bool SetVideoResolution(int width, int height);
bool SetVideoFrameRate(int frame_rate);
+ bool SetMediaFormat(int width, int height, int frame_rate, const std::string &format);
+ void SetDecodeCodec(const std::string &codec);
+ void AddDataChannel(void);
void AttachSignals(bool is_source, bool need_display);
void DetachSignals(void);
// Cautions : Event handler is not a pointer. So, change event_handle after Set Event handler
std::string GetLocalDescription(void) const { return local_description_; };
void PrintStats(void);
+ bool IsPlayingState(void);
private:
static void OnOfferCreated(webrtc_h webrtc, const char *description, void *user_data);
static void OnTrackAdded(webrtc_h webrtc, webrtc_media_type_e type, unsigned int id,
void *user_data);
static void OnDataChannelOpen(webrtc_data_channel_h channel, void *user_data);
+ static void OnBufferStateChanged(unsigned int id,
+ webrtc_media_packet_source_buffer_state_e state, void *user_data);
bool IsNegotiatingState(void);
- bool IsPlayingState(void);
bool IsRedundantCandidate(const std::string &candidate);
+ static void *GetMediaFormatHandler(int width, int height, int frame_rate,
+ const std::string &format);
private:
webrtc_h webrtc_handle_;
+ webrtc_media_source_type_e source_type_;
webrtc_data_channel_h channel_;
unsigned int source_id_;
std::string local_description_;
TEST_F(WebRtcStreamTest, test_Create_WebRtcStream_OnDevice)
{
WebRtcStream src_stream{};
- EXPECT_EQ(true, src_stream.Create(true, false)) << "Failed to create source stream";
}
TEST_F(WebRtcStreamTest, test_Start_WebRtcSrcStream_OnDevice)
{
WebRtcStream stream{};
- EXPECT_EQ(true, stream.Create(true, false)) << "Failed to create source stream";
- EXPECT_EQ(true, stream.AttachCameraSource()) << "Failed to attach camera source";
+ stream.AddDataChannel();
+ stream.AttachSignals(true, false);
+
+ stream.SetSourceType(WEBRTC_MEDIA_SOURCE_TYPE_CAMERA);
+ EXPECT_EQ(true, stream.ActivateSource()) << "Failed to attach camera source";
stream.GetEventHandler().SetOnStateChangedCb(
std::bind(OnStreamStateChanged, std::placeholders::_1, std::ref(stream), this));
TEST_F(WebRtcSourceOffererTest, test_Start_WebRtcStream_OnDevice)
{
- EXPECT_EQ(true, src_stream_.Create(true, false)) << "Failed to create source stream";
- EXPECT_EQ(true, src_stream_.AttachCameraSource()) << "Failed to attach camera source";
+ src_stream_.AddDataChannel();
+ src_stream_.AttachSignals(true, false);
+ src_stream_.SetSourceType(WEBRTC_MEDIA_SOURCE_TYPE_CAMERA);
+ EXPECT_EQ(true, src_stream_.ActivateSource()) << "Failed to attach camera source";
src_stream_.GetEventHandler().SetOnStateChangedCb(
std::bind(OnSrcStreamStateChanged, std::placeholders::_1, std::ref(src_stream_), this));
OnSrcIceGatheringStateNotify, std::placeholders::_1, std::ref(src_stream_), this));
src_stream_.Start();
- EXPECT_EQ(true, sink_stream_.Create(false, false)) << "Failed to create sink stream";
+ sink_stream_.AddDataChannel();
+ sink_stream_.AttachSignals(false, false);
sink_stream_.GetEventHandler().SetOnStateChangedCb(
std::bind(OnSinkStreamStateChanged, std::placeholders::_1, std::ref(sink_stream_), this));
TEST_F(WebRtcSinkOffererTest, test_Start_WebRtcStream_OnDevice)
{
- EXPECT_EQ(true, src_stream_.Create(true, false)) << "Failed to create source stream";
- EXPECT_EQ(true, src_stream_.AttachCameraSource()) << "Failed to attach camera source";
+ src_stream_.AddDataChannel();
+ src_stream_.AttachSignals(true, false);
+ src_stream_.SetSourceType(WEBRTC_MEDIA_SOURCE_TYPE_CAMERA);
+ EXPECT_EQ(true, src_stream_.ActivateSource()) << "Failed to attach camera source";
auto on_src_stream_state_changed_cb =
std::bind(OnSrcStreamStateChanged, std::placeholders::_1, std::ref(src_stream_), this);
src_stream_.GetEventHandler().SetOnStateChangedCb(on_src_stream_state_changed_cb);
OnSrcIceGatheringStateNotify, std::placeholders::_1, std::ref(src_stream_), this));
src_stream_.Start();
- EXPECT_EQ(true, sink_stream_.Create(false, false)) << "Failed to create sink stream";
+ src_stream_.AddDataChannel();
+ src_stream_.AttachSignals(false, false);
sink_stream_.GetEventHandler().SetOnStateChangedCb(
std::bind(OnSinkStreamStateChanged, std::placeholders::_1, std::ref(sink_stream_), this));
BuildRequires: pkgconfig(libmosquitto)
BuildRequires: pkgconfig(openssl1.1)
%if %{use_glib}
-BuildRequires: pkgconfig(capi-media-camera)
BuildRequires: pkgconfig(capi-media-player)
BuildRequires: pkgconfig(capi-media-image-util)
BuildRequires: pkgconfig(capi-media-sound-manager)
FAIL() << "Unexpected exception: " << e.what();
}
}
+
+#define MEDIA_FORMAT_I420 "I420"
+TEST_F(AITTWEBRTCTest, Set_Source_Type_Media_Packet_P)
+{
+ try {
+ publisher->SetConfig("SOURCE_TYPE", "MEDIA_PACKET");
+ publisher->SetConfig("WIDTH", std::to_string(HD_WIDTH));
+ publisher->SetConfig("HEIGHT", std::to_string(HD_HEIGHT));
+ publisher->SetConfig("FRAME_RATE", std::to_string(FRAME_RATE_10));
+ publisher->SetConfig("MEDIA_FORMAT", MEDIA_FORMAT_I420);
+
+ subscriber->SetReceiveCallback(
+ [&](AittStream *stream, void *obj, void *user_data) {
+ if (stream == nullptr) {
+ printf("Invalid stream\n");
+ return;
+ }
+
+ DBG("ReceiveCallback Called");
+ if (g_main_loop_is_running(main_loop))
+ g_main_loop_quit(main_loop);
+ },
+ nullptr);
+ subscriber->Start();
+ publisher->Start();
+
+ g_main_loop_run(main_loop);
+ } catch (std::exception &e) {
+ FAIL() << "Unexpected exception: " << e.what();
+ }
+}
#endif
class AITTRTSPTest : public testing::Test {