void AlsaPMO::WorkerThread(void) { void *pBuffer; Error eErr; int iRet = -1; Event *pEvent; snd_pcm_channel_status_t ainfo; // Don't do anything until resume is called. m_pPauseSem->Wait(); // Sleep for a pre buffer period PreBuffer(); // The following should be abstracted out into the general thread // classes: #ifdef __linux__ struct sched_param sParam; sParam.sched_priority = sched_get_priority_max(SCHED_OTHER); pthread_setschedparam(pthread_self(), SCHED_OTHER, &sParam); #endif ainfo.channel = SND_PCM_CHANNEL_PLAYBACK; for(; !m_bExit;) { if (m_bPause) { m_pPauseSem->Wait(); continue; } // Loop until we get an Init event from the LMC if (!m_properlyInitialized) { pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent(); if (pEvent == NULL) { m_pLmc->Wake(); WasteTime(); continue; } if (pEvent->Type() == PMO_Init) { if (IsError(Init(((PMOInitEvent *)pEvent)->GetInfo()))) { delete pEvent; break; } } delete pEvent; continue; } // Set up reading a block from the buffer. If not enough bytes are // available, sleep for a little while and try again. for(;;) { eErr = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, m_iDataSize); if (eErr == kError_EndOfStream || eErr == kError_Interrupt) break; if (eErr == kError_NoDataAvail) { m_pLmc->Wake(); CheckForBufferUp(); WasteTime(); continue; } // Is there an event pending that we need to take care of // before we play this block of samples? if (eErr == kError_EventPending) { pEvent = ((EventBuffer *)m_pInputBuffer)->PeekEvent(); if (pEvent == NULL) continue; if (pEvent->Type() == PMO_Quit && ((EventBuffer *)m_pInputBuffer)->GetNumBytesInBuffer() > 0) { if (WaitForDrain()) { Reset(true); m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting)); return; } continue; } pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent(); if (pEvent->Type() == PMO_Init) Init(((PMOInitEvent *)pEvent)->GetInfo()); if (pEvent->Type() == PMO_Reset) Reset(false); if (pEvent->Type() == PMO_Info) HandleTimeInfoEvent((PMOTimeInfoEvent *)pEvent); if (pEvent->Type() == PMO_Quit) { delete pEvent; m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting)); return; } delete pEvent; continue; } if (IsError(eErr)) { ReportError("Internal error occured."); m_pContext->log->Error("Cannot read from buffer in PMO " "worker tread: %d\n", eErr); break; } break; } // Now write the block to the audio device. If the block doesn't // all fit, pause and loop until the entire block has been played. // This loop could be written using non-blocking io... for(;!m_bExit && !m_bPause;) { iRet = snd_pcm_write(m_handle,pBuffer,m_iDataSize); if (iRet == -EAGAIN) { CheckForBufferUp(); WasteTime(); continue; } if (iRet == -EIO) { snd_pcm_channel_prepare(m_handle, SND_PCM_CHANNEL_PLAYBACK); continue; } break; } if (m_bExit) { m_pInputBuffer->EndRead(0); return; } if (m_bPause) { if (iRet == -EAGAIN) m_pInputBuffer->EndRead(0); else { m_pInputBuffer->EndRead(iRet); UpdateBufferStatus(); } continue; } if (iRet < 0) { m_pInputBuffer->EndRead(0); ReportError("Could not write sound data to the soundcard."); m_pContext->log->Error("Failed to write to the soundcard: %s\n", strerror(errno)); break; } m_pInputBuffer->EndRead(iRet); m_pLmc->Wake(); UpdateBufferStatus(); } }
void SoundCardPMO::WorkerThread(void) { void *pBuffer; Error eErr; size_t iRet; Event *pEvent; // audio_info info; bool bPerfWarn = false; // Don't do anything until resume is called. m_pPauseSem->Wait(); // Wait a specified prebuffer time... PreBuffer(); // The following should be abstracted out into the general thread // classes: #ifdef __linux__ struct sched_param sParam; sParam.sched_priority = sched_get_priority_max(SCHED_OTHER); pthread_setschedparam(pthread_self(), SCHED_OTHER, &sParam); #endif for(; !m_bExit;) { if (m_bPause) { m_pPauseSem->Wait(); continue; } // Loop until we get an Init event from the LMC if (!m_properlyInitialized) { pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent(); if (pEvent == NULL) { m_pLmc->Wake(); WasteTime(); continue; } if (pEvent->Type() == PMO_Init) { if (IsError(Init(((PMOInitEvent *)pEvent)->GetInfo()))) { delete pEvent; break; } } delete pEvent; continue; } // Set up reading a block from the buffer. If not enough bytes are // available, sleep for a little while and try again. for(;;) { eErr = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, m_iDataSize); if (eErr == kError_EndOfStream || eErr == kError_Interrupt) break; if (eErr == kError_NoDataAvail) { m_pLmc->Wake(); if (!bPerfWarn) { time_t t; time(&t); m_pContext->log->Log(LogPerf, "Output buffer underflow: %s", ctime(&t)); bPerfWarn = true; } WasteTime(); continue; } // Is there an event pending that we need to take care of // before we play this block of samples? if (eErr == kError_EventPending) { pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent(); if (pEvent->Type() == PMO_Init) Init(((PMOInitEvent *)pEvent)->GetInfo()); if (pEvent->Type() == PMO_Reset) Reset(false); if (pEvent->Type() == PMO_Info) HandleTimeInfoEvent((PMOTimeInfoEvent *)pEvent); if (pEvent->Type() == PMO_Quit) { delete pEvent; if (WaitForDrain()) m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting)); return; } delete pEvent; continue; } if (IsError(eErr)) { ReportError("Internal error occured."); m_pContext->log->Error("Cannot read from buffer in PMO " "worker tread: %d\n", eErr); break; } bPerfWarn = false; break; } // Now write the block to the audio device. If the block doesn't // all fit, pause and loop until the entire block has been played. // This loop could be written using non-blocking io... for(;;) { if (m_bExit || m_bPause) break; // ioctl(audio_fd, AUDIO_GETINFO, &info); if (0) //((unsigned)(info.fragments * info.fragsize) < m_iDataSize) { WasteTime(); continue; } break; } if (m_bExit || m_bPause) { m_pInputBuffer->EndRead(0); continue; } iRet = write(audio_fd, pBuffer, m_iDataSize); // write(audio_fd, pBuffer, 0); // for WaitForDrain(), maybe? if (iRet < 0) { m_pInputBuffer->EndRead(0); ReportError("Could not write sound data to the soundcard."); m_pContext->log->Error("Failed to write to the soundcard: %s\n", strerror(errno)); break; } m_iTotalBytesWritten += iRet; m_pInputBuffer->EndRead(iRet); m_pLmc->Wake(); UpdateBufferStatus(); } }
/* individual buffers */ void PushFrame(unsigned short* in_frame) { static int discard_me = 1; /* we discard the first slow frame, since it's probably a partial */ unsigned int i_in, i_out; int i, j, k, curr_index; int write_ok; #if DAS_CARDS > 0 unsigned B0, B1; #endif int range, first, c; unsigned short *frame; first = PreBuffer(in_frame); if (first == -1) return; range = first >> 8; first &= 0xff; /* Wait for dirfile initialisation */ while (!ri.dirfile_init) usleep(10000); for (c = 0; c < range; ++c) { if (c != range - 1) defile_flags |= DEFILE_FLAG_INSERTED_FRAME; frame = pre_buffer[(first + c) % FAST_PER_SLOW]; #ifdef DEBUG_FASTSAMP printf("Fastsamp push: %lu\n", *(unsigned long*)(&frame[1])); #endif /* slow data */ curr_index = frame[3]; #ifdef DEBUG_SEQUENCING static int next_j = -1; if (next_j > -1 && next_j != curr_index) printf("frame %lli sequencing error: expected %i but got %i\n", fc, next_j, curr_index); next_j = (curr_index + 1) % FAST_PER_SLOW; #endif if (curr_index < FAST_PER_SLOW) for (i = 0; i < slowsPerBi0Frame; i++) slow_data[curr_index][i] = frame[slow_fields[curr_index][i].i0]; /* defile flags */ defile_flag_buf[curr_index] = defile_flags; defile_flags = 0; /* fast data */ memcpy(fast_frame[curr_index], frame, DiskFrameSize); /* do while loop blocks until sufficient buffers empty */ do { write_ok = 1; /* ****************************************************************** */ /* First make sure there is enough space in ALL the buffers */ /* We need to do it first and all at once to maintain synchronization */ /* We discard the full frame id there is no space */ /* ****************************************************************** */ /************************************/ /* Check buffer space in slow field */ /************************************/ for (i = 0; write_ok && i < slowsPerBi0Frame; i++) for (j = 0; write_ok && j < FAST_PER_SLOW; j++) { i_in = (slow_fields[j][i].i_in + 1) % MAXBUF; if(i_in == slow_fields[j][i].i_out) write_ok = 0; } /* Check buffer space in defile_field */ if (write_ok) { i_out = defile_field.i_out; i_in = defile_field.i_in; if (i_out <= i_in) i_out += MAXBUF; if (i_in + FAST_PER_SLOW >= i_out) write_ok = 0; } /****************************************** * Check buffer space in normal fast data * *****************************************/ if (write_ok) for (j = 0; write_ok && j < n_fast; j++) { i_out = normal_fast[j].i_out; i_in = normal_fast[j].i_in; if (i_out <= i_in) i_out += MAXBUF; if(i_in + FAST_PER_SLOW >= i_out) write_ok = 0; } #if DAS_CARDS > 0 /******************************************* * Check buffer space in fast bolo data * *******************************************/ if (write_ok) for (i = 0; write_ok && i < DAS_CARDS; i++) for (j = 0; write_ok && j < DAS_CHS; j += 2) { i_out = bolo_fields[i][j].i_out; i_in = bolo_fields[i][j].i_in; if (i_out <= i_in) i_out += MAXBUF; if(i_in + FAST_PER_SLOW >= i_out) write_ok = 0; } #endif if (!write_ok) usleep(10000); } while (!write_ok); /*************************/ /* PUSH RX FRAME TO DISK */ /*************************/ /* push if we're at the end of a frame... */ if (curr_index == FAST_PER_SLOW - 1) { if (discard_me) /* discard the first frame */ discard_me = 0; else { /* Slow Data */ for (i = 0; i < slowsPerBi0Frame; i++) { for (j = 0; j < FAST_PER_SLOW; j++) { i_in = slow_fields[j][i].i_in; ((unsigned short*)slow_fields[j][i].b)[i_in] = slow_data[j][i]; if (++i_in >= MAXBUF) i_in = 0; slow_fields[j][i].i_in = i_in; } } for (k = 0; k < FAST_PER_SLOW; ++k) { /* defile_field */ i_in = defile_field.i_in; ((unsigned short*)defile_field.b)[i_in] = defile_flag_buf[k]; defile_field.i_in = (i_in + 1) % MAXBUF; /********************/ /* normal fast data */ /********************/ for (j = 0; j < n_fast; j++) { i_in = normal_fast[j].i_in; if (normal_fast[j].size == 2) ((unsigned*)normal_fast[j].b)[i_in] = *((unsigned*)(fast_frame[k] + normal_fast[j].i0)); else ((unsigned short*)normal_fast[j].b)[i_in] = fast_frame[k][normal_fast[j].i0]; normal_fast[j].i_in = (i_in + 1) % MAXBUF; } #if DAS_CARDS > 0 /********************/ /* fast bolo data */ /********************/ for (i = 0; i < DAS_CARDS; i++) { for (j = 0; j < DAS_CHS; j += 2) { B0 = (unsigned)fast_frame[k][boloIndex[i][j][0] + BoloBaseIndex] + (((unsigned)fast_frame[k][boloIndex[i][j][1] + BoloBaseIndex] & 0xff00) << 8); B1 = fast_frame[k][boloIndex[i][j + 1][0] + BoloBaseIndex] + ((fast_frame[k][boloIndex[i][j + 1][1] + BoloBaseIndex] & 0x00ff) << 16); i_in = bolo_fields[i][j].i_in; ((unsigned*)bolo_fields[i][j].b)[i_in] = B0; ((unsigned*)bolo_fields[i][j + 1].b)[i_in] = B1; bolo_fields[i][j].i_in = bolo_fields[i][j + 1].i_in = (i_in + 1) % MAXBUF; } } #endif } } } } }
void SoundCardPMO::WorkerThread(void) { void *pBuffer; Error eErr; size_t iRet; Event *pEvent; audio_buf_info info; bool bPerfWarn = false; // Don't do anything until resume is called. m_pPauseSem->Wait(); //CheckForBufferUp(); // Wait a specified prebuffer time... PreBuffer(); for(; !m_bExit;) { if (m_bPause) { m_pPauseSem->Wait(); continue; } // Loop until we get an Init event from the LMC if (!m_properlyInitialized) { pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent(); if (pEvent == NULL) { m_pLmc->Wake(); WasteTime(); continue; } if (pEvent->Type() == PMO_Init) { if (IsError(Init(((PMOInitEvent *)pEvent)->GetInfo()))) { delete pEvent; break; } } delete pEvent; continue; } // Set up reading a block from the buffer. If not enough bytes are // available, sleep for a little while and try again. for(;;) { eErr = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, m_iDataSize); if (eErr == kError_EndOfStream || eErr == kError_Interrupt) break; if (eErr == kError_NoDataAvail) { m_pLmc->Wake(); CheckForBufferUp(); if (!bPerfWarn) { time_t t; time(&t); m_pContext->log->Log(LogPerf, "Output buffer underflow: %s", ctime(&t)); bPerfWarn = true; } WasteTime(); continue; } // Is there an event pending that we need to take care of // before we play this block of samples? if (eErr == kError_EventPending) { pEvent = ((EventBuffer *)m_pInputBuffer)->PeekEvent(); if (pEvent == NULL) continue; if (pEvent->Type() == PMO_Quit && ((EventBuffer *)m_pInputBuffer)->GetNumBytesInBuffer() > 0) { if (WaitForDrain()) { m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting)); return; } continue; } pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent(); if (pEvent->Type() == PMO_Init) Init(((PMOInitEvent *)pEvent)->GetInfo()); if (pEvent->Type() == PMO_Reset) Reset(false); if (pEvent->Type() == PMO_Info) HandleTimeInfoEvent((PMOTimeInfoEvent *)pEvent); if (pEvent->Type() == PMO_Quit) { delete pEvent; m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting)); return; } delete pEvent; continue; } if (IsError(eErr)) { ReportError("Internal error occured."); m_pContext->log->Error("Cannot read from buffer in PMO " "worker tread: %d\n", eErr); break; } bPerfWarn = false; break; } if (m_bExit || m_bPause) { m_pInputBuffer->EndRead(0); continue; } iRet = ALwritesamps(outaudioport, pBuffer, m_iDataSize); if ((int)iRet < 0) { m_pInputBuffer->EndRead(0); ReportError("Could not write sound data to the soundcard."); m_pContext->log->Error("Failed to write to the soundcard: %s\n", strerror(errno)); break; } m_iTotalBytesWritten += iRet; m_pInputBuffer->EndRead(iRet); m_pLmc->Wake(); UpdateBufferStatus(); } }
/* Initialise dirfile */ void InitialiseDirFile(int reset, unsigned long offset) { dtrace("%i, %lu", reset, offset); FILE* fp; int fd; int j, i, is_bolo = 0; #if DAS_CARDS > 0 char field[FIELD_LEN]; int bolo_node; char first_bolo_buf[16]; #endif char gpb[GPB_LEN]; char ext[4] = ""; fc = 0; #ifdef HAVE_LIBZ if (rc.gzip_output) { defileclose = &gzclose; strcpy(ext, ".gz"); } else #endif defileclose = &close; rc.resume_at = -1; if (mkdir(rc.dirfile, 00755) < 0) if (!CheckWriteAllow(errno)) berror(fatal, "cannot create dirfile `%s'", rc.dirfile); bprintf(info, "\nWriting to dirfile `%s'\n", rc.dirfile); rc.dirname = strdup(rc.dirfile); snprintf(rc.dirname, strlen(rc.dirfile), "%s", basename(rc.dirfile)); for (i = 0; i < FAST_PER_SLOW + 10; ++i) { pre_buffer[i] = balloc(fatal, DiskFrameSize); pre_buffer[i][3] = i; } /* Reset the PreBuffer */ PreBuffer(NULL); for (i = 0; i < FAST_PER_SLOW; ++i) fast_frame[i] = balloc(fatal, DiskFrameSize); /*********************************** * create and fill the format file * ***********************************/ sprintf(gpb, "%s/format", rc.dirfile); if ((fd = creat(gpb, 0666)) < 0) berror(fatal, "cannot create format file `%s/format'", rc.dirfile); PathSplit_r(rc.dirfile, NULL, gpb); WriteFormatFile(fd, atoi(gpb), offset / FAST_PER_SLOW); #ifdef __SPIDER__ if (rc.extra_format) { sprintf(gpb, "/INCLUDE /data/etc/spider/format.mce_mplex\n" "/INCLUDE /data/etc/spider/format.bolo_stats\n"); if (write(fd, gpb, strlen(gpb)) < 0) berror(err, "Error writing to format file\n"); } #else /* no extra format for BLAST */ #endif if (close(fd) < 0) berror(fatal, "Error while closing format file"); /* DEFILE_FLAGS */ sprintf(gpb, "%s/DEFILE_FLAGS%s", rc.dirfile, ext); defile_field.size = 1; defile_field.fp = OpenField(1, 1, gpb); defile_field.i0 = 1; if (reset) { if (rc.resume_at > 0) defile_field.nw = rc.resume_at; else defile_field.nw = 0; } defile_field.i_in = defile_field.i_out = 0; defile_field.b = balloc(fatal, MAXBUF * sizeof(unsigned short)); /* FASTSAMP */ sprintf(gpb, "%s/FASTSAMP%s", rc.dirfile, ext); normal_fast[0].size = 2; normal_fast[0].fp = OpenField(1, 2, gpb); normal_fast[0].i0 = 1; if (reset) { if (rc.resume_at > 0) normal_fast[0].nw = rc.resume_at; else normal_fast[0].nw = 0; } normal_fast[0].i_in = normal_fast[0].i_out = 0; normal_fast[0].b = balloc(fatal, MAXBUF * sizeof(unsigned int)); n_fast = 1; //original form /* slow chs */ for (i = 0; i < slowsPerBi0Frame; i++) { for (j = 0; j < FAST_PER_SLOW; j++) { if (strlen(SlowChList[i][j].field) > 0) { slow_fields[j][i].size = FieldSize(SlowChList[i][j].type, SlowChList[i][j].field); sprintf(gpb, "%s/%s%s", rc.dirfile, SlowChList[i][j].field, ext); slow_fields[j][i].fp = OpenField(0, slow_fields[j][i].size, gpb); } else slow_fields[j][i].fp = -1; slow_fields[j][i].i_in = slow_fields[j][i].i_out = 0; if (reset) { if (rc.resume_at > 0) slow_fields[j][i].nw = rc.resume_at / FAST_PER_SLOW; else slow_fields[j][i].nw = 0; } slow_fields[j][i].b = balloc(fatal, 2 * MAXBUF); slow_fields[j][i].i0 = SLOW_OFFSET + i; } } /* normal fast chs */ #if DAS_CARDS > 0 sprintf(first_bolo_buf, "n%02dc00lo", DAS_START+1); #endif for (i = 0; i < ccFast + ccWideFast; i++) { #if DAS_CARDS > 0 if (strcmp(FastChList[i].field, first_bolo_buf) == 0) { bolo_i0 = i + SLOW_OFFSET + slowsPerBi0Frame; is_bolo = 1; } else if (ccDecom > 0 && strcmp(FastChList[i].field, DecomChannels[0].field) == 0) { is_bolo = 0; } #endif if (!is_bolo && strlen(FastChList[i].field) > 0) { normal_fast[n_fast].size = FieldSize(FastChList[i].type, FastChList[i].field); sprintf(gpb, "%s/%s%s", rc.dirfile, FastChList[i].field, ext); normal_fast[n_fast].fp = OpenField(1, normal_fast[n_fast].size, gpb); normal_fast[n_fast].i0 = i + SLOW_OFFSET + slowsPerBi0Frame; normal_fast[n_fast].i_in = normal_fast[n_fast].i_out = 0; if (reset) { if (rc.resume_at > 0) normal_fast[n_fast].nw = rc.resume_at; else normal_fast[n_fast].nw = 0; } normal_fast[n_fast].b = balloc(fatal, MAXBUF * 2 * normal_fast[n_fast].size); n_fast++; } } #if DAS_CARDS > 0 /* special (bolo) fast chs */ bolo_node = DAS_START; for (i = 0; i < DAS_CARDS; i++) { bolo_node++; if (bolo_node%4 == 0) bolo_node++; for (j = 0; j < DAS_CHS; j++) { bolo_fields[i][j].size = 2; sprintf(field, "n%02dc%02d", bolo_node, j); sprintf(gpb, "%s/%s%s", rc.dirfile, field, ext); bolo_fields[i][j].fp = OpenField(1, 2, gpb); bolo_fields[i][j].i_in = bolo_fields[i][j].i_out = 0; if (reset) { if (rc.resume_at > 0) bolo_fields[i][j].nw = rc.resume_at; else bolo_fields[i][j].nw = 0; } bolo_fields[i][j].b = balloc(fatal, MAXBUF * 4); bolo_fields[i][j].i0 = bolo_i0 + i * (DAS_CARDS * 3 / 2) + j; } } #endif if (rc.write_curfile) { // create the link file char lnkfile[1024]; char curfile[1024]; strncpy(curfile, rc.output_curfile, 1018); strcat(curfile, ".cur"); strncpy(lnkfile, rc.output_curfile, 1018); strcat(lnkfile, ".lnk"); unlink(lnkfile); if (symlink(rc.dirfile, lnkfile)<0) { berror(fatal, "could not create link from `%s' to `%s'", rc.dirfile, lnkfile); } // create the cur file if ((fp = fopen(curfile, "w")) == NULL) berror(fatal, "cannot create curfile `%s'", curfile); fprintf(fp, "%s\n", rc.dirfile); if (fclose(fp) < 0) berror(fatal, "cannot close curfile `%s'", curfile); } ri.dirfile_init = 1; }