error_code filelib_write_show(char *buf, u_long size) { if ((int)size > m_ringbuf.Size()) { CLog::Log(LOGERROR, "Shoutcast chunk too big: %lu", size); return SR_ERROR_BUFFER_FULL; } while (m_ringbuf.GetMaxWriteSize() < (int)size) Sleep(10); m_ringbuf.WriteBinary(buf, size); m_ripFile.Write( buf, size ); //will only write, if it has to return SR_SUCCESS; }
bool COrganyaCodec::Init(const std::string& strFile, unsigned int filecache, int& channels, int& samplerate, int& bitspersample, int64_t& totaltime, int& bitrate, AEDataFormat& format, std::vector<AEChannel>& channelinfo) { sample_buffer.Create(4096); kodi::vfs::CFile file; file.OpenFile(strFile); if (!file.OpenFile(strFile, 0)) return false; std::string temp = kodi::GetSettingString("__addonpath__") + "/resources/samples"; tune = org_decoder_create(&file, temp.c_str(), 1); tune->state.sample_rate = 48000; totaltime = org_decoder_get_total_samples(tune)*1000/48000; length = totaltime/1000*48000*4; format = AE_FMT_S16NE; channelinfo = { AE_CH_FL, AE_CH_FR, AE_CH_NULL }; channels = 2; bitspersample = 16; bitrate = 0.0; samplerate = 48000; file.Close(); Seek(0); return true; }
void allbuttests::samplednotlast() { RingItemHeader h = {sizeof(RingItemHeader), 1234}; pProd->put(&h, sizeof(h)); pProd->put(&h, sizeof(h)); CAllButPredicate p; p.addExceptionType(1234, true); ASSERT(p(*pCons)); EQ(sizeof(h), pCons->availableData()); ASSERT(!p(*pCons)); }
void allbuttests::notinlist() { RingItemHeader h = {sizeof(RingItemHeader), 1234}; pProd->put(&h, sizeof(h)); CAllButPredicate p; ASSERT(!p(*pCons)); }
/* Write data to ring buffer from another ring buffer object specified by * 'rBuf'. */ bool CRingBuffer::WriteData(CRingBuffer &rBuf, unsigned int size) { CSingleLock lock(m_critSection); if (m_buffer == NULL) Create(size); bool bOk = size <= rBuf.getMaxReadSize() && size <= getMaxWriteSize(); if (bOk) { unsigned int readpos = rBuf.getReadPtr(); unsigned int chunksize = std::min(size, rBuf.getSize() - readpos); bOk = WriteData(&rBuf.getBuffer()[readpos], chunksize); if (bOk && chunksize < size) bOk = WriteData(&rBuf.getBuffer()[0], size - chunksize); } return bOk; }
void allbuttests::inlist() { RingItemHeader h = {sizeof(RingItemHeader), 1234}; pProd->put(&h, sizeof(h)); CAllButPredicate p; p.addExceptionType(1234); ASSERT(p(*pCons)); }
/* Read in data from the ring buffer to another ring buffer object specified by * 'rBuf'. */ bool CRingBuffer::ReadData(CRingBuffer &rBuf, unsigned int size) { CSingleLock lock(m_critSection); if (rBuf.getBuffer() == NULL) rBuf.Create(size); bool bOk = size <= rBuf.getMaxWriteSize() && size <= getMaxReadSize(); if (bOk) { unsigned int chunksize = std::min(size, m_size - m_readPtr); bOk = rBuf.WriteData(&getBuffer()[m_readPtr], chunksize); if (bOk && chunksize < size) bOk = rBuf.WriteData(&getBuffer()[0], size - chunksize); if (bOk) SkipBytes(size); } return bOk; }
void CFileShoutcast::Close() { OutputDebugString("Shoutcast Stopping\n"); if ( m_ripFile.IsRecording() ) m_ripFile.StopRecording(); m_ringbuf.Clear(); rip_manager_stop(); m_ripFile.Reset(); OutputDebugString("Shoutcast Stopped\n"); }
int COrganyaCodec::ReadPCM(uint8_t* pBuffer, int size, int &actualsize) { if (pos >= length*48000*4/1000) return 1; if (sample_buffer.getMaxReadSize() == 0) { int16_t temp[1024*2]; int64_t written=1024; written = org_decode_samples(tune, temp, written); if (written == 0) return 1; sample_buffer.WriteData((const char*)temp, written*4); } int tocopy = std::min(size, (int)sample_buffer.getMaxReadSize()); sample_buffer.ReadData((char*)pBuffer, tocopy); pos += tocopy; actualsize = tocopy; return 0; }
unsigned int CFileShoutcast::Read(void* lpBuf, __int64 uiBufSize) { if (m_fileState.bRipDone) { OutputDebugString("Read done\n"); return 0; } while (m_ringbuf.GetMaxReadSize() <= 0) Sleep(10); int iRead = m_ringbuf.GetMaxReadSize(); if (iRead > uiBufSize) iRead = (int)uiBufSize; m_ringbuf.ReadBinary((char*)lpBuf, iRead); if (timeGetTime() - m_dwLastTime > 500) { m_dwLastTime = timeGetTime(); CMusicInfoTag tag; GetMusicInfoTag(tag); g_infoManager.SetCurrentSongTag(tag); } return iRead; }
/* * Reads the received numberOfScans scans from the device. If not enough data is available (errorCode == 2) or the application buffer overruns (errorCode == 1), this method returns false. * float* destBuffer: the array that returns the received data from the application data buffer. Data is aligned as follows: element at position destBuffer[scanIndex * numChannels + channelIndex] is sample of channel channelIndex (zero-based) of the scan with zero-based scanIndex. channelIndex ranges from 0..numChannelsPerDevices where numChannelsPerDevice the total number of channels of the device including the trigger line. * int numberOfScans: the number of scans to retrieve from the application buffer. */ bool ReadData(float* destBuffer, int numberOfScans, int *errorCode, string *errorMessage) { int numChannels = NUMBER_OF_CHANNELS + (int) ENABLE_TRIGGER; int validPoints = numChannels * numberOfScans; //wait until requested amount of data is ready if (_buffer.GetSize() < validPoints) { *errorCode = 2; *errorMessage = "Not enough data available"; return false; } //acquire lock on the application buffer for reading _bufferLock.Lock(); __try { //if buffer run over report error and reset buffer if (_bufferOverrun) { _buffer.Reset(); *errorCode = 1; *errorMessage = "Error on reading data from the application data buffer: buffer overrun."; _bufferOverrun = false; return false; } //copy the data from the application buffer into the destination buffer _buffer.Read(destBuffer, validPoints); } __finally { _bufferLock.Unlock(); } *errorCode = 0; *errorMessage = "No error occured."; return true; }
CFileShoutcast::~CFileShoutcast() { // FIXME: without this check // the playback stops when CFile::Stat() // or CFile::Exists() is called // Has this object initialized the ripper? if (m_pShoutCastRipper==this) { rip_manager_stop(); m_pShoutCastRipper = NULL; m_ripFile.Reset(); m_ringbuf.Destroy(); } }
TEST(TestRingBuffer, General) { CRingBuffer a; char data[20]; unsigned int i; EXPECT_TRUE(a.Create(20)); EXPECT_EQ((unsigned int)20, a.getSize()); memset(data, 0, sizeof(data)); for (i = 0; i < a.getSize(); i++) EXPECT_TRUE(a.WriteData(data, 1)); a.Clear(); memcpy(data, "0123456789", sizeof("0123456789")); EXPECT_TRUE(a.WriteData(data, sizeof("0123456789"))); EXPECT_STREQ("0123456789", a.getBuffer()); memset(data, 0, sizeof(data)); EXPECT_TRUE(a.ReadData(data, 5)); EXPECT_STREQ("01234", data); }
CFileShoutcast::CFileShoutcast() { // FIXME: without this check // the playback stops when CFile::Stat() // or CFile::Exists() is called // Do we already have another file // using the ripper? if (!m_pShoutCastRipper) { m_fileState.bBuffering = true; m_fileState.bRipDone = false; m_fileState.bRipStarted = false; m_fileState.bRipError = false; m_ringbuf.Create(1024*1024); // must be big enough. some stations use 192kbps. m_pShoutCastRipper = this; } }
//Starts the thread that does the data acquisition. void StartAcquisition() { int numChannels = NUMBER_OF_CHANNELS + (int) ENABLE_TRIGGER; _isRunning = true; _bufferOverrun = false; //give main process (the data processing thread) high priority HANDLE hProcess = GetCurrentProcess(); SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS); //initialize application data buffer to the specified number of seconds _buffer.Initialize(BUFFER_SIZE_SECONDS * SAMPLE_RATE_HZ * numChannels); //reset event _dataAcquisitionStopped.ResetEvent(); //create data acquisition thread with high priority _dataAcquisitionThread = AfxBeginThread(DoAcquisition, NULL, THREAD_PRIORITY_TIME_CRITICAL,0, CREATE_SUSPENDED); _dataAcquisitionThread->ResumeThread(); }
/** * Put data into the ring. * Each data item is assumed to be preceded by a two longword header of the form: * struct header { * uint32_t size; * uint32_t type * }; * * Futhermore, from the point of view of byte ordering, the type field only has * nonzero bits in the lower order 16 bits. * * We're going to put each data item in the ring atomically. * If there are left over data in the buffer, that will be shifted down * to the beginning of the buffer and * the remaining size will be returned: * * @param ring - reference to the target ring buffer. * @param pBuffer - Pointer to the data buffer. * @param nBytes - Number of bytes in the data buffer. * * It is assumed that the total buffer size will be larger than * needed to hold the largest item. That's controld by the * --mindata switch in any event. */ static size_t putData(CRingBuffer& ring, void* pBuffer, size_t nBytes) { struct header *pHeader; uint8_t* p = reinterpret_cast<uint8_t*>(pBuffer); // makes addr arithmetic easier. struct header *pLastItem; int lastSize = 0; while(nBytes > sizeof(struct header)) { pHeader = reinterpret_cast<struct header*>(p); uint32_t size = computeSize(pHeader); if (size <= nBytes) { // we can put a complete item pLastItem = pHeader; ring.put(p, size); p += size; nBytes -= size; lastSize = size; } else { // We don't have a complete packet. // Move the remainder of the buffer down to the start // must use memmove because this could be an overlapping // move break; } } if (nBytes > 0) { memmove(pBuffer, p, nBytes); } return nBytes; // Residual data. }
/* * Starts data acquisition and acquires data until StopAcquisition is called (i.e., the _isRunning flag is set to false) * Then the data acquisition will be stopped. */ unsigned int DoAcquisition(LPVOID pArgs) { int queueIndex = 0; int numChannels = NUMBER_OF_CHANNELS + (int) ENABLE_TRIGGER; int nPoints = NUMBER_OF_SCANS * numChannels; DWORD numValidBytes = nPoints * sizeof(float); DWORD bufferSizeBytes = (DWORD) ceil(numValidBytes / (double) MAX_USB_PACKET_SIZE) * MAX_USB_PACKET_SIZE; int timeOutMilliseconds = (int) ceil(2000 * (NUMBER_OF_SCANS / (double) SAMPLE_RATE_HZ)); DWORD numBytesReceived = 0; //create the temporary data buffers (the device will write data into those) BYTE** buffers = new BYTE*[QUEUE_SIZE]; OVERLAPPED* overlapped = new OVERLAPPED[QUEUE_SIZE]; __try { //for each data buffer allocate a number of numValidBytes bytes for (queueIndex = 0; queueIndex < QUEUE_SIZE; queueIndex++) { buffers[queueIndex] = new BYTE[bufferSizeBytes]; SecureZeroMemory(&(overlapped[queueIndex]), sizeof(OVERLAPPED)); //create a windows event handle that will be signaled when new data from the device has been received for each data buffer overlapped[queueIndex].hEvent = CreateEvent(NULL, false, false, NULL); } queueIndex = 0; //start device if (!GT_Start(_hDevice)) { cout << "\tError on GT_Start: Couldn't start data acquisition of device.\n"; PrintDeviceErrorMessage(); return 0; } //queue up the first batch of transfer requests to prevent overflow on the device for (queueIndex = 0; queueIndex < QUEUE_SIZE; queueIndex++) { if (!GT_GetData(_hDevice, buffers[queueIndex], bufferSizeBytes, &overlapped[queueIndex])) { cout << "\tError on GT_GetData.\n"; PrintDeviceErrorMessage(); return 0; } } queueIndex = 0; //continouos data acquisition while (_isRunning) { //wait for notification from the system telling that new data is available if (WaitForSingleObject(overlapped[queueIndex].hEvent, 5000) == WAIT_TIMEOUT) { cout << "\tError on data transfer: timeout occured.\n"; PrintDeviceErrorMessage(); return 0; } //get number of actually received bytes... if (!GT_GetOverlappedResult(_hDevice, &overlapped[queueIndex], &numBytesReceived, false)) { cout << "\tError on data transfer: couldn't receive number of transferred bytes (GT_GetOverlappedResult() returned FALSE; Windows error code: " << GetLastError() << ")\n"; return 0; } //...and check if we lost something (number of received bytes must be equal to the previously allocated buffer size) if (numBytesReceived != numValidBytes) { cout << "\tError on data transfer: samples lost.\n"; return 0; } //to store the received data into the application data buffer at once, lock it _bufferLock.Lock(); __try { //if we are going to overrun on writing the received data into the buffer, set the appropriate flag; the reading thread will handle the overrun _bufferOverrun = (_buffer.GetFreeSize() < nPoints); //store received data in the correct order (that is scan-wise, where one scan includes all channels) _buffer.Write((float*) buffers[queueIndex], nPoints); } __finally { //release the previously acquired lock _bufferLock.Unlock(); } //add new GetData call to the queue replacing the currently received one if (!GT_GetData(_hDevice, buffers[queueIndex], bufferSizeBytes, &overlapped[queueIndex])) { cout << "\tError on GT_GetData.\n"; PrintDeviceErrorMessage(); return 0; } //signal processing (main) thread that new data is available _newDataAvailable.SetEvent(); //increment circular queueIndex to process the next queue at the next loop repitition (on overrun start at index 0 again) queueIndex = (queueIndex + 1) % QUEUE_SIZE; } } __finally { cout << "Stopping device and cleaning up..." << "\n"; //stop device if (!GT_Stop(_hDevice)) { cout << "\tError on GT_Stop: couldn't stop device.\n"; PrintDeviceErrorMessage(); } //clean up allocated resources for (int i = 0; i < QUEUE_SIZE; i++) { if (WaitForSingleObject(overlapped[queueIndex].hEvent, timeOutMilliseconds) == WAIT_TIMEOUT) GT_ResetTransfer(_hDevice); CloseHandle(overlapped[queueIndex].hEvent); delete [] buffers[queueIndex]; //increment queue index queueIndex = (queueIndex + 1) % QUEUE_SIZE; } delete [] buffers; delete [] overlapped; //reset _isRunning flag _isRunning = false; //signal event _dataAcquisitionStopped.SetEvent(); //end thread AfxEndThread(0xdead); } return 0xdead; }
bool CFileShoutcast::Open(const CURL& url, bool bBinary) { m_dwLastTime = timeGetTime(); int ret; CGUIDialogProgress* dlgProgress = (CGUIDialogProgress*)m_gWindowManager.GetWindow(WINDOW_DIALOG_PROGRESS); set_rip_manager_options_defaults(&m_opt); strcpy(m_opt.output_directory, "./"); m_opt.proxyurl[0] = '\0'; // Use a proxy, if the GUI was configured as such bool bProxyEnabled = g_guiSettings.GetBool("network.usehttpproxy"); if (bProxyEnabled) { const CStdString &strProxyServer = g_guiSettings.GetString("network.httpproxyserver"); const CStdString &strProxyPort = g_guiSettings.GetString("network.httpproxyport"); // Should we check for valid strings here #ifndef _LINUX _snprintf( m_opt.proxyurl, MAX_URL_LEN, "http://%s:%s", strProxyServer.c_str(), strProxyPort.c_str() ); #else snprintf( m_opt.proxyurl, MAX_URL_LEN, "http://%s:%s", strProxyServer.c_str(), strProxyPort.c_str() ); #endif } CStdString strUrl; url.GetURL(strUrl); strUrl.Replace("shout://", "http://"); printf("Opening url: %s\n", strUrl.c_str()); strncpy(m_opt.url, strUrl.c_str(), MAX_URL_LEN); sprintf(m_opt.useragent, "x%s", url.GetFileName().c_str()); if (dlgProgress) { dlgProgress->SetHeading(260); dlgProgress->SetLine(0, 259); dlgProgress->SetLine(1, strUrl); dlgProgress->SetLine(2, ""); if (!dlgProgress->IsDialogRunning()) dlgProgress->StartModal(); dlgProgress->Progress(); } if ((ret = rip_manager_start(rip_callback, &m_opt)) != SR_SUCCESS) { if (dlgProgress) dlgProgress->Close(); return false; } int iShoutcastTimeout = 10 * SHOUTCASTTIMEOUT; //i.e: 10 * 10 = 100 * 100ms = 10s int iCount = 0; while (!m_fileState.bRipDone && !m_fileState.bRipStarted && !m_fileState.bRipError && (!dlgProgress || !dlgProgress->IsCanceled())) { if (iCount <= iShoutcastTimeout) //Normally, this isn't the problem, //because if RIP_MANAGER fails, this would be here //with m_fileState.bRipError { Sleep(100); } else { if (dlgProgress) { dlgProgress->SetLine(1, 257); dlgProgress->SetLine(2, "Connection timed out..."); Sleep(1500); dlgProgress->Close(); } return false; } iCount++; } if (dlgProgress && dlgProgress->IsCanceled()) { Close(); dlgProgress->Close(); return false; } /* store content type of stream */ m_contenttype = rip_manager_get_content_type(); //CHANGED CODE: Don't reset timer anymore. while (!m_fileState.bRipDone && !m_fileState.bRipError && m_fileState.bBuffering && (!dlgProgress || !dlgProgress->IsCanceled())) { if (iCount <= iShoutcastTimeout) //Here is the real problem: Sometimes the buffer fills just to //slowly, thus the quality of the stream will be bad, and should be //aborted... { Sleep(100); char szTmp[1024]; //g_dialog.SetCaption(0, "Shoutcast" ); sprintf(szTmp, "Buffering %i bytes", m_ringbuf.GetMaxReadSize()); if (dlgProgress) { dlgProgress->SetLine(2, szTmp ); dlgProgress->Progress(); } sprintf(szTmp, "%s", m_ripInfo.filename); for (int i = 0; i < (int)strlen(szTmp); i++) szTmp[i] = tolower((unsigned char)szTmp[i]); szTmp[50] = 0; if (dlgProgress) { dlgProgress->SetLine(1, szTmp ); dlgProgress->Progress(); } } else //it's not really a connection timeout, but it's here, //where things get boring, if connection is slow. //trust me, i did a lot of testing... Doesn't happen often, //but if it does it sucks to wait here forever. //CHANGED: Other message here { if (dlgProgress) { dlgProgress->SetLine(1, 257); dlgProgress->SetLine(2, "Connection to server too slow..."); dlgProgress->Close(); } return false; } iCount++; } if (dlgProgress && dlgProgress->IsCanceled()) { Close(); dlgProgress->Close(); return false; } if ( m_fileState.bRipError ) { if (dlgProgress) { dlgProgress->SetLine(1, 257); dlgProgress->SetLine(2, m_errorInfo.error_str); dlgProgress->Progress(); Sleep(1500); dlgProgress->Close(); } return false; } if (dlgProgress) { dlgProgress->SetLine(2, 261); dlgProgress->Progress(); dlgProgress->Close(); } return true; }
//this is the main entry point of the application void main(int argc, _TCHAR* argv[]) { zmq::context_t context(1); zmq::socket_t publisher(context, ZMQ_PUB); publisher.bind("tcp://192.168.56.101:5556"); CStopWatch timer; try { cout << "Opening device '" << _deviceSerial << "'...\n"; //open device _hDevice = GT_OpenDevice(0); //_hDevice = GT_OpenDeviceEx(_deviceSerial); if (_hDevice == NULL) throw string("Error on GT_OpenDeviceEx: couldn't open device ").append(_deviceSerial); cout << "Configuring device...\n"; int nossr = 0; int nof; GT_GetNumberOfFilter(&nof); cout<<"nof: "<<nof<<endl; FILT* flt = new FILT[nof]; GT_GetFilterSpec(flt); for (int i=0; i< nof; i++) { cout<<i<<":"<<flt[i].fu<<":"<<flt[i].fo<<":"<<flt[i].fs<<":"<<flt[i].type<<endl; } //GT_GetNumberOfSupportedSampleRates(_hDevice, &nossr); //cout<<"nossr: "<<nossr<<endl; /*GT_GetNumberOfSupportedSampleRates(_hDevice, &nossr); float* ssr = new float[nossr]; GT_GetSupportedSampleRates(_hDevice, ssr); for (int i=0; i<nossr; i++) cout<<ssr[i]<<endl; */ GT_Stop(_hDevice); GT_ResetTransfer(_hDevice); //configure device ConfigureDevice(_hDevice); /*GT_HIAMP_CHANNEL_IMPEDANCES imp; for (int i = 0; i<256; i++) { imp.IsActiveElectrode[i]=FALSE; imp.Impedance[i]=0.0; } BOOL status = GT_GetImpedance(_hDevice, &imp); cout<<"imp: "<<status<<" : "; for (int i = 0; i<10; i++) { cout<<imp.Impedance[i]<<" "; } cout<<endl; Sleep(200);*/ //Sleep(2000); //determine how many scans should be read and processed at once by the processing thread (not the acquisition thread!) int numScans = NUMBER_OF_SCANS; int numChannels = NUMBER_OF_CHANNELS + (int) ENABLE_TRIGGER; //initialize temporary data buffer where data from the application buffer will be copied out float *receivedData = new float[numScans * numChannels]; try { //for receiving error messages from ReadData int errorCode; string errorMessage; //initialize file stream where received data should be written to //CFile outputFile; //if (!outputFile.Open(_T("receivedData.bin"), CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) // throw string("Error on creating/opening output file: file 'receivedData.bin' couldn't be opened."); try { cout<<sizeof(float)<<" "<<sizeof(double)<<endl; cout << "Starting acquisition...\n"; //start data acquisition StartAcquisition(); //cout << "Receiving data for " << NUM_SECONDS_RUNNING << " seconds...\n"; cout << "Receiving data ...\n"; //to stop the application after a specified time, get start time long startTime = clock(); long endTime = startTime + NUM_SECONDS_RUNNING * CLOCKS_PER_SEC; //this is the data processing thread; data received from the devices will be written out to a file here //while (clock() < endTime) timer.startTimer(); while (!_kbhit()) { //to release CPU resources wait until the acquisition thread tells that new data has been received and is available in the buffer. WaitForSingleObject(_newDataAvailable.m_hObject, 1000); while (_buffer.GetSize() >= numScans * numChannels) { //read data from the application buffer and stop application if buffer overrun if (!ReadData(receivedData, numScans, &errorCode, &errorMessage)) { if (errorCode == 2) break; else throw errorMessage; } timer.stopTimer(); //cout<<"t: "<<setprecision(12)<<timer.getElapsedTime()<<endl; //stringstream ss; //ss<<setprecision(9)<<timer.getElapsedTime()<<" "; //for (size_t i=0; i<numScans * numChannels; i++) { // ss<<receivedData[i]<<" "; //} //zmq::message_t message(ss.str().size()+1); zmq::message_t message(sizeof(double) + sizeof(float)* numScans * numChannels); //memcpy(message.data(), ss.str().c_str(), ss.str().size()+1); double ct = timer.getElapsedTime(); memcpy(message.data(), &ct, sizeof(double)); memcpy((char *) (message.data())+sizeof(double), receivedData, sizeof(float)* numScans * numChannels); publisher.send(message); //timer.startTimer(); //cout<<"m:"<<ss.str().c_str()<<endl; //write data to file //outputFile.Write(receivedData, numScans * numChannels * sizeof(float)); //cout<<"d1: "<<receivedData[64]<<endl; //cout<<sizeof(float)<<endl; } } } catch (string& exception) { //an exception occured during data acquisition cout << "\t" << exception << "\n"; //continue execution in every case to clean up allocated resources (since no finally-block exists) } // //in every case, stop data acquisition and clean up allocated resources //since no finally statement exists in c++ and we can't mix it with the C __finally statement, the clean-up code follows the try-catch block. // //stop data acquisition StopAcquisition(); //close output file //outputFile.Close(); } catch (string& exception) { //an exception occured cout << "\t" << exception << "\n"; //continue execution in every case to clean up allocated resources (since no finally-block exists) } cout << "Closing device...\n"; //close device if (!GT_CloseDevice(&_hDevice)) cout << "Error on GT_CloseDevice: couldn't close device" << GetDeviceErrorMessage() << "\n"; //free allocated resources delete [] receivedData; cout << "Clean up complete. Bye bye!" << "\n\n"; } catch (string& exception) { //in case an error occured during opening and initialization, report it and stop execution cout << "\t" << exception << "\n\n"; } publisher.close(); cout << "Press ENTER to exit..."; getchar(); }
/* Append all content from ring buffer 'rBuf' to this ring buffer */ bool CRingBuffer::Append(CRingBuffer &rBuf) { return WriteData(rBuf, rBuf.getMaxReadSize()); }