#include #include #include #include #include #include #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 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(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(pSample); temp = const_cast(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(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() */