Skip to content

Commit

Permalink
Add millicast support (closes CoSMoSoftware#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
murillo128 committed Jul 24, 2018
1 parent 6a2d062 commit 6554179
Show file tree
Hide file tree
Showing 16 changed files with 653 additions and 2 deletions.
6 changes: 6 additions & 0 deletions UI/window-basic-auto-config-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ void AutoConfigTestPage::TestBandwidthThread()
case 3: serverType = "webrtc_spankchain";
break;

case 4: serverType = "webrtc_millicast";
break;

default: blog(LOG_WARNING, "serverType does not exist");
break;
}
Expand Down Expand Up @@ -973,6 +976,9 @@ void AutoConfigTestPage::FinalizeResults()
case 3: serverType = "webrtc_spankchain";
break;

case 4: serverType = "webrtc_millicast";
break;

default: blog(LOG_WARNING, "serverType does not exist");
break;
}
Expand Down
21 changes: 20 additions & 1 deletion UI/window-basic-auto-config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ AutoConfigStreamPage::AutoConfigStreamPage(QWidget *parent)
ui->streamType->addItem(obs_service_get_display_name("rtmp_custom"));
ui->streamType->addItem(obs_service_get_display_name("webrtc_janus"));
ui->streamType->addItem(obs_service_get_display_name("webrtc_spankchain"));
ui->streamType->addItem(obs_service_get_display_name("webrtc_millicast"));

setTitle(QTStr("Basic.AutoConfig.StreamPage"));
setSubTitle(QTStr("Basic.AutoConfig.StreamPage.SubTitle"));
Expand Down Expand Up @@ -294,6 +295,9 @@ bool AutoConfigStreamPage::validatePage()
case 3: serverType = "webrtc_spankchain";
break;

case 4: serverType = "webrtc_millicast";
break;

default:blog(LOG_ERROR, "streamType do not exist");
break;
}
Expand Down Expand Up @@ -436,6 +440,18 @@ void AutoConfigStreamPage::ServiceChanged()
ui->serverStackedWidget->setVisible(true);
ui->serverLabel->setVisible(true);

ui->streamKeyLabel->setVisible(true);
ui->key->setVisible(true);
ui->show->setVisible(true);
} else if (ui->streamType->currentIndex() == 4) { //webrtc_millicast
ui->formLayout->insertRow(1, ui->serverLabel,
ui->serverStackedWidget);

ui->region->setVisible(false);
ui->serverStackedWidget->setCurrentIndex(1);
ui->serverStackedWidget->setVisible(true);
ui->serverLabel->setVisible(true);

ui->streamKeyLabel->setVisible(true);
ui->key->setVisible(true);
ui->show->setVisible(true);
Expand Down Expand Up @@ -673,6 +689,8 @@ AutoConfig::AutoConfig(QWidget *parent)
customServer = 2;
} else if (serviceType.compare("webrtc_spankchain") == 0) {
customServer = 3;
} else if (serviceType.compare("webrtc_millicast") == 0) {
customServer = 4;
} else {
blog(LOG_ERROR, "streamType do not exist");
}
Expand Down Expand Up @@ -849,7 +867,8 @@ void AutoConfig::SaveStreamSettings()

case 3: service_id = "webrtc_spankchain";
break;

case 4: service_id = "webrtc_millicast";
break;
default: blog(LOG_ERROR, "streamType do not exist");
break;
}
Expand Down
4 changes: 4 additions & 0 deletions UI/window-basic-main-outputs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,8 @@ bool SimpleOutput::StartStreaming(obs_service_t *service)
type = "janus_output";
} else if (typeCheck.find("spankchain") != std::string::npos) {
type = "spankchain_output";
} else if (typeCheck.find("millicast") != std::string::npos) {
type = "millicast_output";
} else {
type = "rtmp_output";
}
Expand Down Expand Up @@ -1431,6 +1433,8 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
type = "janus_output";
} else if (typeCheck.find("spankchain") != std::string::npos) {
type = "spankchain_output";
} else if (typeCheck.find("millicast") != std::string::npos) {
type = "millicast_output";
} else {
type = "rtmp_output";
}
Expand Down
2 changes: 2 additions & 0 deletions plugins/obs-outputs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ set( obs-outputs_HEADERS
rtmp-stream.h
janus-stream.h
spankchain-stream.h
millicast-stream.h
net-if.h
AudioDeviceModuleWrapper.h
VideoCapture.h
Expand All @@ -147,6 +148,7 @@ set( obs-outputs_SOURCES
rtmp-stream.c
janus-stream.cpp
spankchain-stream.cpp
millicast-stream.cpp
rtmp-windows.c
AudioDeviceModuleWrapper.cpp
VideoCapturer.cpp
Expand Down
3 changes: 2 additions & 1 deletion plugins/obs-outputs/WebRTCStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ class WebRTCStream : public rtc::RefCountedObject<WebRTCStreamInterface>
public:
enum Type {
Janus = 0,
SpankChain = 1
SpankChain = 1,
Millicast = 2
};
public:
WebRTCStream(obs_output_t *output);
Expand Down
164 changes: 164 additions & 0 deletions plugins/obs-outputs/millicast-stream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#include <stdio.h>
#include <obs-module.h>
#include <obs-avc.h>
#include <util/platform.h>
#include <util/dstr.h>
#include <util/threading.h>
#include <inttypes.h>
#include <rtc_base/platform_file.h>
#include <rtc_base/bitrateallocationstrategy.h>
#include <modules/audio_processing/include/audio_processing.h>

#define warn(format, ...) blog(LOG_WARNING, format, ##__VA_ARGS__)
#define info(format, ...) blog(LOG_INFO, format, ##__VA_ARGS__)
#define debug(format, ...) blog(LOG_DEBUG, format, ##__VA_ARGS__)

#define OPT_DROP_THRESHOLD "drop_threshold_ms"
#define OPT_PFRAME_DROP_THRESHOLD "pframe_drop_threshold_ms"
#define OPT_MAX_SHUTDOWN_TIME_SEC "max_shutdown_time_sec"
#define OPT_BIND_IP "bind_ip"
#define OPT_NEWSOCKETLOOP_ENABLED "new_socket_loop_enabled"
#define OPT_LOWLATENCY_ENABLED "low_latency_mode_enabled"

#include "WebRTCStream.h"

extern "C" const char *millicast_stream_getname(void *unused)
{
info("millicast_stream_getname");
UNUSED_PARAMETER(unused);
return obs_module_text("MILLICASTStream");
}


extern "C" void millicast_stream_destroy(void *data)
{
info("millicast_stream_destroy");
//Get stream
WebRTCStream* stream = (WebRTCStream*)data;
//Stop it
stream->stop();
//Remove ref and let it self destroy
stream->Release();
}

extern "C" void *millicast_stream_create(obs_data_t *settings, obs_output_t *output)
{
info("millicast_stream_create");
//Create new stream
WebRTCStream* stream = new WebRTCStream(output);
//Don't allow it to be deleted
stream->AddRef();
//Return it
return (void*)stream;
}

extern "C" void millicast_stream_stop(void *data, uint64_t ts)
{
info("millicast_stream_stop");
//Get stream
WebRTCStream* stream = (WebRTCStream*)data;
//Stop it
stream->stop();
//Remove ref and let it self destroy
stream->Release();
}

extern "C" bool millicast_stream_start(void *data)
{
info("millicast_stream_start");
//Get stream
WebRTCStream* stream = (WebRTCStream*)data;
//Don't allow it to be deleted
stream->AddRef();
//Start it
return stream->start(WebRTCStream::Millicast);
}

extern "C" void millicast_receive_video(void *data, struct video_data *frame)
{
//Get stream
WebRTCStream* stream = (WebRTCStream*)data;
//Process audio
stream->onVideoFrame(frame);
}
extern "C" void millicast_receive_audio(void *data, struct audio_data *frame)
{
//Get stream
WebRTCStream* stream = (WebRTCStream*)data;
//Process audio
stream->onAudioFrame(frame);
}

extern "C" void millicast_stream_defaults(obs_data_t *defaults)
{
info("millicast_stream_defaults");
obs_data_set_default_int(defaults, OPT_DROP_THRESHOLD, 700);
obs_data_set_default_int(defaults, OPT_PFRAME_DROP_THRESHOLD, 900);
obs_data_set_default_int(defaults, OPT_MAX_SHUTDOWN_TIME_SEC, 30);
obs_data_set_default_string(defaults, OPT_BIND_IP, "default");
obs_data_set_default_bool(defaults, OPT_NEWSOCKETLOOP_ENABLED, false);
obs_data_set_default_bool(defaults, OPT_LOWLATENCY_ENABLED, false);
}

extern "C" obs_properties_t *millicast_stream_properties(void *unused)
{
info("millicast_stream_properties");
UNUSED_PARAMETER(unused);

obs_properties_t *props = obs_properties_create();

obs_properties_add_int(props, OPT_DROP_THRESHOLD,
obs_module_text("MILLICASTStream.DropThreshold"),
200, 10000, 100);

obs_properties_add_bool(props, OPT_NEWSOCKETLOOP_ENABLED,
obs_module_text("MILLICASTStream.NewSocketLoop"));
obs_properties_add_bool(props, OPT_LOWLATENCY_ENABLED,
obs_module_text("MILLICASTStream.LowLatencyMode"));

return props;
}

extern "C" uint64_t millicast_stream_total_bytes_sent(void *data)
{
//Get stream
WebRTCStream* stream = (WebRTCStream*)data;
return stream->getBitrate ();
}

extern "C" int millicast_stream_dropped_frames(void *data)
{
return 0;
}

extern "C" float millicast_stream_congestion(void *data)
{
return 0.0f;
}

extern "C" {
struct obs_output_info millicast_output_info = {
"millicast_output", //id
OBS_OUTPUT_AV | OBS_OUTPUT_SERVICE | OBS_OUTPUT_MULTI_TRACK, //flags
millicast_stream_getname, //get_name
millicast_stream_create, //create
millicast_stream_destroy, //destroy
millicast_stream_start, //start
millicast_stream_stop, //stop
millicast_receive_video, //raw_video
millicast_receive_audio, //raw_audio
nullptr, //encoded_packet
nullptr, //update
millicast_stream_defaults, //get_defaults
millicast_stream_properties, //get_properties
nullptr, //pause
millicast_stream_total_bytes_sent, //get_total_bytes
millicast_stream_dropped_frames, //get_dropped_frame
nullptr, //type_data
nullptr, ////free_type_data
millicast_stream_congestion, //get_congestion
nullptr, //get_connect_time_ms
"vp8", //encoded_video_codecs
"opus" //encoded_audio_codecs
};
}
111 changes: 111 additions & 0 deletions plugins/obs-outputs/millicast-stream.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include <obs-module.h>
#include <obs-avc.h>
#include <util/platform.h>
#include <util/circlebuf.h>
#include <util/dstr.h>
#include <util/threading.h>
#include <inttypes.h>
#include "librtmp/rtmp.h"
#include "librtmp/log.h"
#include "flv-mux.h"
#include "net-if.h"

#ifdef _WIN32
#include <Iphlpapi.h>
#else
#include <sys/ioctl.h>
#endif

#define do_log(level, format, ...) \
blog(level, "[spankchain stream: '%s'] " format, \
obs_output_get_name(stream->output), ##__VA_ARGS__)

#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)

#define OPT_DROP_THRESHOLD "drop_threshold_ms"
#define OPT_PFRAME_DROP_THRESHOLD "pframe_drop_threshold_ms"
#define OPT_MAX_SHUTDOWN_TIME_SEC "max_shutdown_time_sec"
#define OPT_BIND_IP "bind_ip"
#define OPT_NEWSOCKETLOOP_ENABLED "new_socket_loop_enabled"
#define OPT_LOWLATENCY_ENABLED "low_latency_mode_enabled"

//#define TEST_FRAMEDROPS

#ifdef TEST_FRAMEDROPS

#define DROPTEST_MAX_KBPS 3000
#define DROPTEST_MAX_BYTES (DROPTEST_MAX_KBPS * 1000 / 8)

struct droptest_info {
uint64_t ts;
size_t size;
};
#endif

struct spankchain_stream {
obs_output_t *output;

pthread_mutex_t packets_mutex;
struct circlebuf packets;
bool sent_headers;

volatile bool connecting;
pthread_t connect_thread;

volatile bool active;
volatile bool disconnected;
pthread_t send_thread;

int max_shutdown_time_sec;

os_sem_t *send_sem;
os_event_t *stop_event;
uint64_t stop_ts;
uint64_t shutdown_timeout_ts;

struct dstr path, key;
struct dstr username, password;
struct dstr encoder_name;
struct dstr bind_ip;

/* frame drop variables */
int64_t drop_threshold_usec;
int64_t min_drop_dts_usec;
int64_t pframe_drop_threshold_usec;
int64_t pframe_min_drop_dts_usec;
int min_priority;
float congestion;

int64_t last_dts_usec;

uint64_t total_bytes_sent;
int dropped_frames;

#ifdef TEST_FRAMEDROPS
struct circlebuf droptest_info;
size_t droptest_size;
#endif

RTMP rtmp;

bool new_socket_loop;
bool low_latency_mode;
bool disable_send_window_optimization;
bool socket_thread_active;
pthread_t socket_thread;
uint8_t *write_buf;
size_t write_buf_len;
size_t write_buf_size;
pthread_mutex_t write_buf_mutex;
os_event_t *buffer_space_available_event;
os_event_t *buffer_has_data_event;
os_event_t *socket_available_event;
os_event_t *send_thread_signaled_exit;
};

#ifdef _WIN32
void *socket_thread_windows(void *data);
#endif

Loading

0 comments on commit 6554179

Please sign in to comment.