int InitClockRate(void) { if ((kmem = open("/dev/kmem", O_RDWR)) == -1) { msyslog(LOG_ERR, "open(/dev/kmem): %m"); perror("adjtimed: open(/dev/kmem)"); return (-1); } nlist("/hp-ux", nl); if (nl[0].n_type == 0) { fputs("adjtimed: /hp-ux has no symbol table\n", stderr); msyslog(LOG_ERR, "/hp-ux has no symbol table"); return (-1); } /* * Set the default to the system's original value */ default_rate = GetClockRate(); if (default_rate == UNKNOWN_RATE) default_rate = DEFAULT_RATE; tick_rate = (MILLION / default_rate); slew_rate = TICK_ADJ * tick_rate; fprintf(stderr,"default_rate=%ld, tick_rate=%ld, slew_rate=%ld\n",default_rate,tick_rate,slew_rate); return (0); } /* InitClockRate */
/* * Reset the clock rate to the default value. */ void ResetClockRate(void) { struct itimerval it; it.it_value.tv_sec = it.it_value.tv_usec = 0L; setitimer(ITIMER_REAL, &it, (struct itimerval *)0); if (verbose > 2) puts("adjtimed: resetting the clock"); if (sysdebug > 2) msyslog(LOG_INFO, "resetting the clock"); if (GetClockRate() != default_rate) { if (SetClockRate(default_rate) == -1) { msyslog(LOG_ERR, "set clock rate: %m"); perror("adjtimed: set clock rate"); } } oldrate = 0.0; } /* ResetClockRate */
USHORT CHalSampleClock::Set( long lRate, long lSource, long lReference, BOOLEAN bForce ) ///////////////////////////////////////////////////////////////////////////// { PLLCLOCKINFO ClockInfo; PHAL8420 pCS8420 = m_pHalAdapter->Get8420(); PHAL4114 pAK4114 = m_pHalAdapter->Get4114(); PHALMIXER pMixer = m_pHalAdapter->GetMixer(); USHORT usDeviceID = m_pHalAdapter->GetDeviceID(); long lOriginalSource = m_lSource; ULONG bWideWireIn; // correct any code that isn't AES16 aware if( pAK4114 && (lSource < MIXVAL_AES16_CLKSRC_INTERNAL) ) lSource += MIXVAL_AES16_CLKSRC_INTERNAL; // if there is no change from current setting, just return. if( (m_lRate == lRate) && (m_lSource == lSource) && (m_lReference == lReference) && !bForce ) // if Force is set, always run the entire routine { return( HSTATUS_OK ); } // if this firmware doesn't support P16, then the lowest sample rate is 11025, not 8000 if( !m_pHalAdapter->HasP16() ) if( lRate < 11025 ) lRate = 11025; // the lowest sample rate for the AES16 is 32kHz, highest is 192kHz if( pAK4114 ) { if( lRate < 32000 ) { lRate = 32000; } if( lRate > 192000 ) { lRate = 192000; } // read the wide wire bit for use later on... pAK4114->GetWideWireIn( &bWideWireIn ); } // if the requested sample rate is less than the minimum rate, set it at the minimum if( lRate < MIN_SAMPLE_RATE ) { lRate = MIN_SAMPLE_RATE; } // if the requested sample rate is greater than the maximum rate, set it at the maximum if( lRate > MAX_SAMPLE_RATE ) { lRate = MAX_SAMPLE_RATE; } if( !bForce ) { // if we are trying to clock from an external input, make sure that input is running at the correct rate if( GetClockRate( &lRate, &lSource, &lReference ) ) { DPF(("CHalSampleClock::GetClockRate Failed!\n")); return( HSTATUS_INVALID_MODE ); } // make sure all the devices are idle if( m_pHalAdapter->GetNumActiveWaveDevices() ) { DPF(("CHalSampleClock::Set: Device in use. Cannot change sample rate.\n")); return( HSTATUS_ALREADY_IN_USE ); } } //DPF(("CHalSampleClock::Set %ld\n", lRate )); // start off with everything turned off RtlZeroMemory( &ClockInfo, sizeof( PLLCLOCKINFO ) ); if( pAK4114 ) ClockInfo.ulClkSrc = lSource - MIXVAL_AES16_CLKSRC_INTERNAL; else ClockInfo.ulClkSrc = lSource; switch( lSource ) { case MIXVAL_L2_CLKSRC_INTERNAL: case MIXVAL_AES16_CLKSRC_INTERNAL: //DPF(("MIXVAL_L2_CLKSRC_INTERNAL\n")); lReference = MIXVAL_CLKREF_AUTO; if( m_pHalAdapter->Has40MHzXtal() ) GetClockInfo( &lRate, tbl40MHzClk, &ClockInfo, ARRAYSIZE(tbl40MHzClk) ); else GetClockInfo( &lRate, tbl32MHzClk, &ClockInfo, ARRAYSIZE(tbl32MHzClk) ); break; case MIXVAL_L2_CLKSRC_EXTERNAL: case MIXVAL_L2_CLKSRC_HEADER: case MIXVAL_AES16_CLKSRC_EXTERNAL: case MIXVAL_AES16_CLKSRC_HEADER: //DPF(("MIXVAL_L2_CLKSRC_EXTERNAL/HEADER\n")); // make sure we allow the change from INTERNAL or DIGITAL if( lReference == MIXVAL_CLKREF_AUTO ) lReference = MIXVAL_CLKREF_27MHZ; switch( lReference ) { case MIXVAL_CLKREF_WORD: //DPF(("MIXVAL_CLKREF_WORD\n")); // Just set the word bit here, the rest will get taken care of later. ClockInfo.ulWord = 1; break; case MIXVAL_CLKREF_WORD256: //DPF(("MIXVAL_CLKREF_WORD256\n")); //Set M,N,P for quad, single, double speed if( lRate > 100000 ) { ClockInfo.ulM = 96; ClockInfo.ulN = 96; ClockInfo.ulP = SR_P2; } else if( lRate > 50000 ) { ClockInfo.ulM = 48; ClockInfo.ulN = 96; ClockInfo.ulP = SR_P2; } else { ClockInfo.ulM = 24; ClockInfo.ulN = 96; ClockInfo.ulP = SR_P4; } break; case MIXVAL_CLKREF_13p5MHZ: //DPF(("MIXVAL_CLKREF_13p5MHZ\n")); GetClockInfo( &lRate, tbl13p5MHzClk, &ClockInfo, ARRAYSIZE(tbl13p5MHzClk) ); break; case MIXVAL_CLKREF_27MHZ: //DPF(("MIXVAL_CLKREF_27MHZ\n")); GetClockInfo( &lRate, tbl27MHzClk, &ClockInfo, ARRAYSIZE(tbl27MHzClk) ); break; default: DPF(("Invalid lReference [%08lx]\n", lReference )); return( HSTATUS_INVALID_MIXER_VALUE ); } break; case MIXVAL_L2_CLKSRC_VIDEO: //DPF(("MIXVAL_L2_CLKSRC_VIDEO\n")); if( usDeviceID == PCIDEVICE_LYNX_L22 ) return( HSTATUS_INVALID_MIXER_VALUE ); lReference = MIXVAL_CLKREF_AUTO; if( m_pHalAdapter->HasTIVideoPLL() ) GetClockInfo( &lRate, tblTIPll_27MHzClk, &ClockInfo, ARRAYSIZE(tblTIPll_27MHzClk) ); else GetClockInfo( &lRate, tbl24MHzClk, &ClockInfo, ARRAYSIZE(tbl24MHzClk) ); break; case MIXVAL_L2_CLKSRC_LSTREAM_PORT1: case MIXVAL_L2_CLKSRC_LSTREAM_PORT2: case MIXVAL_AES16_CLKSRC_LSTREAM: //DPF(("MIXVAL_L2_CLKSRC_LSTREAM_PORTX\n")); lReference = MIXVAL_CLKREF_WORD; // force to word // Just set the word bit here, the rest will get taken care of later. ClockInfo.ulWord = 1; break; case MIXVAL_AES16_CLKSRC_DIGITAL_2: case MIXVAL_AES16_CLKSRC_DIGITAL_3: // rev NC AES16 boards can only sync to digital in 1 & 2 if( pAK4114 && !m_pHalAdapter->GetPCBRev() ) return( HSTATUS_INVALID_MIXER_VALUE ); case MIXVAL_L2_CLKSRC_DIGITAL: case MIXVAL_AES16_CLKSRC_DIGITAL_0: case MIXVAL_AES16_CLKSRC_DIGITAL_1: //DPF(("MIXVAL_L2_CLKSRC_DIGITAL\n")); lReference = MIXVAL_CLKREF_AUTO; // force to auto // Just set the word bit here, the rest will get taken care of later. ClockInfo.ulWord = 1; break; default: DPF(("Invalid lSource [%08lx]\n", lSource )); return( HSTATUS_INVALID_MIXER_VALUE ); } // if this is a word clock, limit the sample rate if( lReference == MIXVAL_CLKREF_WORD ) { if( m_lReference != lReference ) { if( lRate < 24000 ) lRate = 44100; } if( lRate < 24000 ) { //DPF(("Invalid Sample Rate for Word Clock!\n")); DPF(("SetSampleRate: Word Clock Below 24000!\n")); return( HSTATUS_INVALID_SAMPLERATE ); } } // Set the speed based on the sample rate if( lRate > 100000 ) ClockInfo.ulSpeed = SR_SPEED_4X; else if( lRate > 50000 ) ClockInfo.ulSpeed = SR_SPEED_2X; else ClockInfo.ulSpeed = SR_SPEED_1X; // if the word bit is set, make sure the M, N & P registers are correct for the speed setting if( ClockInfo.ulWord ) { ClockInfo.ulM = 1; // Ignored ClockInfo.ulBypassM = 1; switch( ClockInfo.ulSpeed ) { case SR_SPEED_1X: ClockInfo.ulN = 1024; ClockInfo.ulP = SR_P4; break; case SR_SPEED_2X: ClockInfo.ulN = 512; ClockInfo.ulP = SR_P2; break; case SR_SPEED_4X: ClockInfo.ulN = 256; ClockInfo.ulP = SR_P2; break; } } // if this is an AES16, and the speed isn't 1X, and widewire is on, and the digital input is the sample clock source // NOTE: WideWire has already been read above if( pAK4114 && (lRate > 50000) && bWideWireIn && ((lSource >= MIXVAL_AES16_CLKSRC_DIGITAL_0) || ((lSource == MIXVAL_AES16_CLKSRC_EXTERNAL) && (lReference == MIXVAL_CLKREF_WORD))) ) { ClockInfo.ulN *= 2; // double the N value } // change the sample rate in hardware //DPF(("Changing Sample Rate in Hardware\n")); if( (usDeviceID == PCIDEVICE_LYNXTWO_A) && !m_pHalAdapter->GetPCBRev() ) // is this a Model A rev NC board? m_RegPLLCTL = MAKE_PLLCTL_L2AREVNC( ClockInfo.ulM, ClockInfo.ulBypassM, ClockInfo.ulN, ClockInfo.ulP, ClockInfo.ulClkSrc, ClockInfo.ulWord, ClockInfo.ulSpeed ); else m_RegPLLCTL = MAKE_PLLCTL( ClockInfo.ulM, ClockInfo.ulBypassM, ClockInfo.ulN, ClockInfo.ulP, ClockInfo.ulClkSrc, ClockInfo.ulWord, ClockInfo.ulSpeed ); //set speed in A/D and D/A // since these writes are slow, update only if there is a speed change. if( m_ulSpeed != ClockInfo.ulSpeed ) { m_pHalAdapter->SetConverterSpeed( lRate ); } // if auto-recalibration is on (which is the default) if( m_pHalAdapter->GetAutoRecalibrate() ) { // if P changed or the sample clock changed, recalibrate the converters if( (m_lSource != lSource) || (m_lReference != lReference) || (m_ulP != ClockInfo.ulP ) ) { m_pHalAdapter->CalibrateConverters(); } } // save the new values if( m_lSource != lSource ) pMixer->ControlChanged( LINE_ADAPTER, LINE_NO_SOURCE, CONTROL_CLOCKSOURCE ); if( m_lReference != lReference ) pMixer->ControlChanged( LINE_ADAPTER, LINE_NO_SOURCE, CONTROL_CLOCKREFERENCE ); if( m_lRate != lRate ) pMixer->ControlChanged( LINE_ADAPTER, LINE_NO_SOURCE, CONTROL_CLOCKRATE ); m_lSource = lSource; m_lReference = lReference; m_lRate = lRate; m_ulSpeed = ClockInfo.ulSpeed; m_ulP = ClockInfo.ulP; // if the Sample Clock Source is Digital, then we must set the 8420 to Mode 3 if( pCS8420 && (m_lSource == MIXVAL_L2_CLKSRC_DIGITAL) ) { // only make the change if the original source was internal if( lOriginalSource == MIXVAL_L2_CLKSRC_INTERNAL ) { pCS8420->SetMode( MIXVAL_SRCMODE_SRC_OFF ); } } // let the 8420 update the digital out channel status. Since the 8420 is opened after // the sample clock, make sure we don't call the 8420 until after the adapter is opened. if( m_pHalAdapter->IsOpen() ) { if( pCS8420 ) pCS8420->SampleClockChanged( m_lRate ); if( pAK4114 ) pAK4114->SampleClockChanged( m_lRate, m_lSource ); m_pHalAdapter->GetLStream()->SampleClockChanged( m_lRate, m_lSource, m_lReference ); } return( HSTATUS_OK ); }
HRESULT Scheduler::ProcessSample(IMFSample *pSample, LONG *plNextSleep) { HRESULT hr = S_OK; LONGLONG hnsPresentationTime = 0; LONGLONG hnsTimeNow = 0; MFTIME hnsSystemTime = 0; BOOL bPresentNow = TRUE; LONG lNextSleep = 0; LONGLONG hnsDelta = 0; if (m_pClock) { // Get the sample's time stamp. It is valid for a sample to // have no time stamp. hr = pSample->GetSampleTime(&hnsPresentationTime); // Get the clock time. (But if the sample does not have a time stamp, // we don't need the clock time.) if (SUCCEEDED(hr)) { hr = m_pClock->GetCorrelatedTime(0, &hnsTimeNow, &hnsSystemTime); } // Calculate the time until the sample's presentation time. // A negative value means the sample is late. hnsDelta = hnsPresentationTime - hnsTimeNow; float fCurrentRate = GetClockRate(); if (fCurrentRate < 0) { // For reverse playback, the clock runs backward. Therefore the delta is reversed. hnsDelta = -hnsDelta; } if (abs(fCurrentRate) > 2) { if (abs(hnsDelta) > m_PerFrameInterval * GetFrameDropThreshold()) { //TRACE((L"ProcessSample: drop sample hnsDelta=%I64d m_PerFrameInterval=%I64d", hnsDelta, m_PerFrameInterval*10)); return hr; } } if (hnsDelta < -m_PerFrame_1_4th) { // This sample is late. //TRACE((L"ProcessSample: sample is late hnsDelta=%I64d", hnsDelta)); bPresentNow = TRUE; } else if (hnsDelta >(3 * m_PerFrame_1_4th)) { // This sample is still too early. Go to sleep. lNextSleep = MFTimeToMsec(hnsDelta - (3 * m_PerFrame_1_4th)); // Adjust the sleep time for the clock rate. (The presentation clock runs // at m_fRate, but sleeping uses the system clock.) lNextSleep = (LONG)(lNextSleep / fabsf(fCurrentRate)); // Don't present yet. bPresentNow = FALSE; } } if (bPresentNow) { hr = m_pCB->PresentSample(pSample, hnsPresentationTime, hnsDelta, m_ScheduledSamples.Count(), m_PerFrame_1_4th); } else { // The sample is not ready yet. Return it to the queue. hr = m_ScheduledSamples.PutBack(pSample); } *plNextSleep = lNextSleep; return hr; }