- #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.setVolume(10);
- int counter = 0;
- char * derp = (char *)pSound;
- for (;;) {
- int addr_size = sizeof(struct sockaddr_in);
- nRet = recvfrom(hSocket,
- derp,
- 60000,
- 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, 30000);
- counter++;
- if(counter == 20)
- {
- stream.play();
- }
- } /* 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() */