#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <SFML/Audio.hpp>
#include <vector>
#include <Windows.h>
#define BUFSIZE 1024
#define MAXADDRSTR 16
#define TIMECAST_ADDR "234.5.6.7"
#define TIMECAST_PORT 8910
// custom audio stream that plays a loaded buffer
class MyStream : public sf::SoundStream
{
public:
std::vector<sf::Int16> m_samples;
std::size_t m_currentSample;
HANDLE sem;
void load(sf::Int16* buffer, size_t sampleCount, size_t sampleRate, size_t channelCount)
{
sem = CreateSemaphore(NULL, 1, 1, NULL);
// extract the audio samples from the sound buffer to our own container
m_samples.assign(buffer, buffer + sampleCount);
// reset the current playing position
m_currentSample = 0;
// initialize the base class
initialize(channelCount, sampleRate);
}
void add(sf::Int16* buffer, size_t size)
{
// check semaphore
WaitForSingleObject(sem, INFINITE);
for (int i = 0; i < size; i++)
{
m_samples.push_back(buffer[i]);
}
ReleaseSemaphore(sem, 1, NULL);
}
private:
virtual bool onGetData(Chunk& data)
{
// number of samples to stream every time the function is called;
// in a more robust implementation, it would rather be a fixed
// amount of time rather than an arbitrary number of samples
const int samplesToStream = 50000;
//check semaphore
WaitForSingleObject(sem, INFINITE);
// set the pointer to the next audio samples to be played
data.samples = &m_samples[m_currentSample];
// have we reached the end of the sound?
if (m_currentSample + samplesToStream <= m_samples.size())
{
// end not reached: stream the samples and continue
data.sampleCount = samplesToStream;
m_currentSample += samplesToStream;
ReleaseSemaphore(sem, 1, NULL);
return true;
}
else
{
// end of stream reached: stream the remaining samples and stop playback
data.sampleCount = m_samples.size() - m_currentSample;
m_currentSample = m_samples.size();
ReleaseSemaphore(sem, 1, NULL);
return false;
}
}
virtual void onSeek(sf::Time timeOffset)
{
// compute the corresponding sample index according to the sample rate and channel count
m_currentSample = static_cast<std::size_t>(timeOffset.asSeconds() * getSampleRate() * getChannelCount());
}
};
char achMCAddr[MAXADDRSTR] = TIMECAST_ADDR;
u_long lMCAddr;
u_short nPort = TIMECAST_PORT;
SYSTEMTIME *lpstSysTime, stSysTime;
int main(int argc, char *argv[]) {
int nRet;
int nIP_TTL = 2;
BOOL fFlag;
SOCKADDR_IN stLclAddr, stSrcAddr;
struct ip_mreq stMreq; /* Multicast interface structure */
SOCKET hSocket;
WSADATA stWSAData;
int count = 0;
// load an audio buffer from a sound file
sf::SoundBuffer buffer;
const sf::Int16* pSample;
sf::Int16 * pSound;
sf::Int16 * temp;
sf::Int16 * test;
size_t sampleCount, sampleRate, channelCount;
buffer.loadFromFile("test.wav");
sampleRate = buffer.getSampleRate();
channelCount = buffer.getChannelCount();
pSample = buffer.getSamples();
sampleCount = buffer.getSampleCount();
pSound = const_cast<sf::Int16*>(pSample);
temp = const_cast<sf::Int16*>(pSample);
test = temp;
char achInBuf [sizeof(sampleRate)];
// initialize and play our custom stream
MyStream stream;
/* Init WinSock */
nRet = WSAStartup(0x0202, &stWSAData);
if (nRet) {
printf ("WSAStartup failed: %d\r\n", nRet);
exit(1);
}
/* Get a datagram socket */
hSocket = socket(AF_INET,
SOCK_DGRAM,
0);
if (hSocket == INVALID_SOCKET) {
printf ("socket() failed, Err: %d\n", WSAGetLastError());
WSACleanup();
exit(1);
}
/* Avoid (WSA)EADDRINUSE error on bind() (last one to bind should
* receive dgrams sent to our port, but there are no guarantees of
* this, unfortunately). */
fFlag = TRUE;
nRet = setsockopt(hSocket,
SOL_SOCKET,
SO_REUSEADDR,
(char *)&fFlag,
sizeof(fFlag));
if (nRet == SOCKET_ERROR) {
printf ("setsockopt() SO_REUSEADDR failed, Err: %d\n",
WSAGetLastError());
}
/* Name the socket (assign the local port number to receive on) */
stLclAddr.sin_family = AF_INET;
stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
stLclAddr.sin_port = htons(nPort);
nRet = bind(hSocket,
(struct sockaddr*) &stLclAddr,
sizeof(stLclAddr));
if (nRet == SOCKET_ERROR) {
printf ("bind() port: %d failed, Err: %d\n", nPort,
WSAGetLastError());
}
/* Join the multicast group so we can receive from it */
stMreq.imr_multiaddr.s_addr = inet_addr(achMCAddr);
stMreq.imr_interface.s_addr = INADDR_ANY;
nRet = setsockopt(hSocket,
IPPROTO_IP,
IP_ADD_MEMBERSHIP,
(char *)&stMreq,
sizeof(stMreq));
if (nRet == SOCKET_ERROR) {
printf(
"setsockopt() IP_ADD_MEMBERSHIP address %s failed, Err: %d\n",
achMCAddr, WSAGetLastError());
}
int addr_size = sizeof(struct sockaddr_in);
stream.load(pSound, 250000, sampleRate, channelCount);
stream.play();
stream.setVolume(10);
char * derp = (char *)pSound;
for (;;) {
int addr_size = sizeof(struct sockaddr_in);
nRet = recvfrom(hSocket,
derp,
sizeof(sampleRate),
0,
(struct sockaddr*)&stSrcAddr,
&addr_size);
if (nRet < 0) {
printf ("recvfrom() failed, Error: %d\n", WSAGetLastError());
WSACleanup();
exit(1);
}
temp = reinterpret_cast<sf::Int16*>(derp);
stream.add(temp, sampleRate);
} /* end for(;;) */
/* Leave the multicast group: With IGMP v1 this is a noop, but
* with IGMP v2, it may send notification to multicast router.
* Even if it's a noop, it's sanitary to cleanup after one's self.
*/
stMreq.imr_multiaddr.s_addr = inet_addr(achMCAddr);
stMreq.imr_interface.s_addr = INADDR_ANY;
nRet = setsockopt(hSocket,
IPPROTO_IP,
IP_DROP_MEMBERSHIP,
(char *)&stMreq,
sizeof(stMreq));
if (nRet == SOCKET_ERROR) {
printf (
"setsockopt() IP_DROP_MEMBERSHIP address %s failed, Err: %d\n",
achMCAddr, WSAGetLastError());
}
/* Close the socket */
closesocket(hSocket);
/* Tell WinSock we're leaving */
WSACleanup();
return (0);
} /* end main() */