Skip to content

Commit

Permalink
Merge pull request #6 from daschuer/1.12-shoutcast-fixes
Browse files Browse the repository at this point in the history
Fix compile on WIN, use GetSystemTimePreciseAsFileTime() on Windows 8
  • Loading branch information
illuusio committed Sep 28, 2015
2 parents 545ef5c + eb6563d commit 2ea06af
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 139 deletions.
73 changes: 46 additions & 27 deletions src/dlgprefshoutcast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "defs_urls.h"
#include "dlgprefshoutcast.h"
#include "shoutcast/defs_shoutcast.h"
#include "controlobjectthread.h"
#include "controlobjectslave.h"

const char* kDefaultMetadataFormat = "$artist - $title";

Expand All @@ -31,12 +31,14 @@ DlgPrefShoutcast::DlgPrefShoutcast(QWidget *parent, ConfigObject<ConfigValue> *_
m_pConfig(_config) {
setupUi(this);

m_pUpdateShoutcastFromPrefs = new ControlObjectThread(
SHOUTCAST_PREF_KEY, "update_from_prefs");
m_pUpdateShoutcastFromPrefs = new ControlObjectSlave(
SHOUTCAST_PREF_KEY, "update_from_prefs", this);
m_pShoutcastEnabled = new ControlObjectSlave(
SHOUTCAST_PREF_KEY, "enabled", this);

// Enable live broadcasting checkbox
enableLiveBroadcasting->setChecked((bool)m_pConfig->getValueString(
ConfigKey(SHOUTCAST_PREF_KEY,"enabled")).toInt());
enableLiveBroadcasting->setChecked(
m_pShoutcastEnabled->toBool());

//Server type combobox
comboBoxServerType->addItem(tr("Icecast 2"), SHOUTCAST_SERVER_ICECAST2);
Expand Down Expand Up @@ -181,7 +183,6 @@ DlgPrefShoutcast::DlgPrefShoutcast(QWidget *parent, ConfigObject<ConfigValue> *_
}

DlgPrefShoutcast::~DlgPrefShoutcast() {
delete m_pUpdateShoutcastFromPrefs;
}

void DlgPrefShoutcast::slotResetToDefaults() {
Expand Down Expand Up @@ -212,31 +213,49 @@ void DlgPrefShoutcast::slotResetToDefaults() {
}

void DlgPrefShoutcast::slotUpdate() {
enableLiveBroadcasting->setChecked((bool)m_pConfig->getValueString(
ConfigKey(SHOUTCAST_PREF_KEY,"enabled")).toInt());
enableLiveBroadcasting->setChecked(m_pShoutcastEnabled->toBool());
}

void DlgPrefShoutcast::slotApply()
{
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "enabled"), ConfigValue(enableLiveBroadcasting->isChecked()));
m_pShoutcastEnabled->set(enableLiveBroadcasting->isChecked());

// Combo boxes, make sure to load their data not their display strings.
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "servertype"), ConfigValue(comboBoxServerType->itemData(comboBoxServerType->currentIndex()).toString()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "bitrate"), ConfigValue(comboBoxEncodingBitrate->itemData(comboBoxEncodingBitrate->currentIndex()).toString()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "format"), ConfigValue(comboBoxEncodingFormat->itemData(comboBoxEncodingFormat->currentIndex()).toString()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "channels"), ConfigValue(comboBoxEncodingChannels->itemData(comboBoxEncodingChannels->currentIndex()).toString()));

m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "mountpoint"), ConfigValue(mountpoint->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "host"), ConfigValue(host->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "port"), ConfigValue(port->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "login"), ConfigValue(login->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "password"), ConfigValue(password->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "stream_name"), ConfigValue(stream_name->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "stream_website"),ConfigValue(stream_website->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "stream_desc"), ConfigValue(stream_desc->toPlainText()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "stream_genre"), ConfigValue(stream_genre->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "stream_public"), ConfigValue(stream_public->isChecked()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "ogg_dynamicupdate"), ConfigValue(ogg_dynamicupdate->isChecked()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "servertype"),
ConfigValue(comboBoxServerType->itemData(
comboBoxServerType->currentIndex()).toString()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "bitrate"),
ConfigValue(comboBoxEncodingBitrate->itemData(
comboBoxEncodingBitrate->currentIndex()).toString()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "format"),
ConfigValue(comboBoxEncodingFormat->itemData(
comboBoxEncodingFormat->currentIndex()).toString()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "channels"),
ConfigValue(comboBoxEncodingChannels->itemData(
comboBoxEncodingChannels->currentIndex()).toString()));

m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "mountpoint"),
ConfigValue(mountpoint->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "host"),
ConfigValue(host->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "port"),
ConfigValue(port->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "login"),
ConfigValue(login->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "password"),
ConfigValue(password->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "stream_name"),
ConfigValue(stream_name->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "stream_website"),
ConfigValue(stream_website->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "stream_desc"),
ConfigValue(stream_desc->toPlainText()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "stream_genre"),
ConfigValue(stream_genre->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "stream_public"),
ConfigValue(stream_public->isChecked()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "ogg_dynamicupdate"),
ConfigValue(ogg_dynamicupdate->isChecked()));

QString charset = "";
if (enableUtf8Metadata->isChecked()) {
Expand All @@ -258,6 +277,6 @@ void DlgPrefShoutcast::slotApply()
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "custom_title"), ConfigValue(custom_title->text()));
m_pConfig->set(ConfigKey(SHOUTCAST_PREF_KEY, "metadata_format"), ConfigValue(metadata_format->text()));

//Tell the EngineShoutcast object to update with these values by toggling this control object.
m_pUpdateShoutcastFromPrefs->slotSet(1.0);
// Tell the EngineShoutcast object to update with these values by toggling this control object.
m_pUpdateShoutcastFromPrefs->set(1.0);
}
5 changes: 3 additions & 2 deletions src/dlgprefshoutcast.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
*@author John Sully
*/

class ControlObjectThread;
class ControlObjectSlave;

class DlgPrefShoutcast : public DlgPreferencePage, public Ui::DlgPrefShoutcastDlg {
Q_OBJECT
Expand All @@ -52,7 +52,8 @@ class DlgPrefShoutcast : public DlgPreferencePage, public Ui::DlgPrefShoutcastDl
private:
ConfigObject<ConfigValue>* m_pConfig;
// If set to 1, EngineShoutcast will update it's settings.
ControlObjectThread* m_pUpdateShoutcastFromPrefs;
ControlObjectSlave* m_pUpdateShoutcastFromPrefs;
ControlObjectSlave* m_pShoutcastEnabled;
};

#endif
68 changes: 59 additions & 9 deletions src/engine/sidechain/enginenetworkstream.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
#ifdef __WINDOWS__
#include <windows.h>
#include "util/performancetimer.h"
#else
#include <sys/time.h>
#include <unistd.h>
#endif

#ifdef __WINDOWS__
// For GetSystemTimeAsFileTime and GetSystemTimePreciseAsFileTime
typedef VOID (WINAPI *PgGetSystemTimeFn)(LPFILETIME);
static PgGetSystemTimeFn s_pfpgGetSystemTimeFn = NULL;
#endif



#include "engine/sidechain/enginenetworkstream.h"

Expand Down Expand Up @@ -40,6 +48,21 @@ EngineNetworkStream::EngineNetworkStream(int numOutputChannels,
if (numInputChannels) {
m_pInputFifo = new FIFO<CSAMPLE>(numInputChannels * kBufferFrames);
}

#ifdef __WINDOWS__
// Resolution:
// 15 ms for GetSystemTimeAsFileTime
// 0.4 ms for GetSystemTimePreciseAsFileTime
// Performance:
// 9 cycles for GetSystemTimeAsFileTime
// 2761 cycles for GetSystemTimePreciseAsFileTime
HMODULE kernel32_dll = LoadLibraryW(L"kernel32.dll");
if (kernel32_dll) {
// for a 0.0004 ms Resolution on Win8
s_pfpgGetSystemTimeFn = (PgGetSystemTimeFn)GetProcAddress(
kernel32_dll, "GetSystemTimePreciseAsFileTime");
}
#endif
}

EngineNetworkStream::~EngineNetworkStream() {
Expand Down Expand Up @@ -131,7 +154,7 @@ void EngineNetworkStream::writeSilence(int frames) {
void EngineNetworkStream::scheduleWorker() {
if (m_pOutputFifo->readAvailable()
>= m_numOutputChannels * kNetworkLatencyFrames) {
m_pWorker->outputAvailabe();
m_pWorker->outputAvailable();
}
}

Expand Down Expand Up @@ -164,21 +187,48 @@ qint64 EngineNetworkStream::getStreamTimeUs() {
qint64 EngineNetworkStream::getNetworkTimeUs() {
// This matches the GPL2 implementation found in
// https://github.com/codders/libshout/blob/a17fb84671d3732317b0353d7281cc47e2df6cf6/src/timing/timing.c
// Instead of ms resuolution we use a us resolution to allow low latency settings
// Instead of ms resolution we use a us resolution to allow low latency settings
// will overflow > 200,000 years
#ifdef __WINDOWS__
FILETIME ft;
int64_t t;
GetSystemTimeAsFileTime(&ft);
return ((qint64)ft.dwHighDateTime << 32 | ft.dwLowDateTime) / 10;
qint64 t;
// no GetSystemTimePreciseAsFileTime available, fall
// back to GetSystemTimeAsFileTime. This happens before
// Windows 8 and Windows Server 2012
// GetSystemTime?AsFileTime is NTP adjusted
// QueryPerformanceCounter depends on the CPU crystal
if(s_pfpgGetSystemTimeFn) {
s_pfpgGetSystemTimeFn(&ft);
return ((qint64)ft.dwHighDateTime << 32 | ft.dwLowDateTime) / 10;
} else {
static qint64 oldNow = 0;
static qint64 incCount = 0;
static PerformanceTimer timerSinceInc;
GetSystemTimeAsFileTime(&ft);
qint64 now = ((qint64)ft.dwHighDateTime << 32 | ft.dwLowDateTime) / 10;
if(now == oldNow) {
// timer was not incremented since last call (< 15 ms)
// Add time since last function call after last increment
// This reduces the jitter < one call cycle which is sufficient
LARGE_INTEGER li;
now += timerSinceInc.elapsed() / 1000;
} else {
// timer was incremented
LARGE_INTEGER li;
timerSinceInc.start();
oldNow = now;
}
return now;
}
#else
struct timeval mtv;
gettimeofday(&mtv, NULL);
return (qint64)(mtv.tv_sec) * 1000000 + mtv.tv_usec;
// CLOCK_MONOTONIC is NTP adjusted
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
#endif
}

void EngineNetworkStream::addWorker(QSharedPointer<SideChainWorker> pWorker) {
void EngineNetworkStream::addWorker(QSharedPointer<NetworkStreamWorker> pWorker) {
m_pWorker = pWorker;
m_pWorker->setOutputFifo(m_pOutputFifo);
}
6 changes: 3 additions & 3 deletions src/engine/sidechain/enginenetworkstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include "util/types.h"
#include "util/fifo.h"
#include "engine/sidechain/sidechainworker.h"
#include "engine/sidechain/networkstreamworker.h"

class EngineNetworkStream {
public:
Expand Down Expand Up @@ -34,7 +34,7 @@ class EngineNetworkStream {

static qint64 getNetworkTimeUs();

void addWorker(QSharedPointer<SideChainWorker> pWorker);
void addWorker(QSharedPointer<NetworkStreamWorker> pWorker);

private:
void scheduleWorker();
Expand All @@ -47,7 +47,7 @@ class EngineNetworkStream {
qint64 m_streamStartTimeUs;
qint64 m_streamFramesWritten;
qint64 m_streamFramesRead;
QSharedPointer<SideChainWorker> m_pWorker;
QSharedPointer<NetworkStreamWorker> m_pWorker;
int m_writeOverflowCount;
};

Expand Down
Loading

0 comments on commit 2ea06af

Please sign in to comment.