Пример #1
0
uint32_t
AudioSink::PlaySilence(uint32_t aFrames)
{
  // Maximum number of bytes we'll allocate and write at once to the audio
  // hardware when the audio stream contains missing frames and we're
  // writing silence in order to fill the gap. We limit our silence-writes
  // to 32KB in order to avoid allocating an impossibly large chunk of
  // memory if we encounter a large chunk of silence.
  const uint32_t SILENCE_BYTES_CHUNK = 32 * 1024;

  AssertOnAudioThread();
  NS_ASSERTION(!mAudioStream->IsPaused(), "Don't play when paused");
  uint32_t maxFrames = SILENCE_BYTES_CHUNK / mInfo.mChannels / sizeof(AudioDataValue);
  uint32_t frames = std::min(aFrames, maxFrames);
  SINK_LOG_V("playing %u frames of silence", aFrames);
  WriteSilence(frames);
  return frames;
}
Пример #2
0
//-------------------------------------------------------------------------
// Description:
//
//  Verifies that the APO is ready to process and locks its state if so.
//
// Parameters:
//
//      u32NumInputConnections - [in] number of input connections attached to this APO
//      ppInputConnections - [in] connection descriptor of each input connection attached to this APO
//      u32NumOutputConnections - [in] number of output connections attached to this APO
//      ppOutputConnections - [in] connection descriptor of each output connection attached to this APO
//
// Return values:
//
//      S_OK                                Object is locked and ready to process.
//      E_POINTER                           Invalid pointer passed to function.
//      APOERR_INVALID_CONNECTION_FORMAT    Invalid connection format.
//      APOERR_NUM_CONNECTIONS_INVALID      Number of input or output connections is not valid on
//                                          this APO.
STDMETHODIMP CSwapAPOMFX::LockForProcess(UINT32 u32NumInputConnections,
    APO_CONNECTION_DESCRIPTOR** ppInputConnections,  
    UINT32 u32NumOutputConnections, APO_CONNECTION_DESCRIPTOR** ppOutputConnections)
{
    ASSERT_NONREALTIME();
    HRESULT hr = S_OK;
    
    hr = CBaseAudioProcessingObject::LockForProcess(u32NumInputConnections,
        ppInputConnections, u32NumOutputConnections, ppOutputConnections);
    IF_FAILED_JUMP(hr, Exit);
    
    if (!IsEqualGUID(m_AudioProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW) && m_fEnableDelayMFX)
    {
        m_nDelayFrames = FRAMES_FROM_HNS(HNS_DELAY);
        m_iDelayIndex = 0;

        m_pf32DelayBuffer.Free();

        // Allocate one second's worth of audio
        // 
        // This allocation is being done using CoTaskMemAlloc because the delay is very large
        // This introduces a risk of glitches if the delay buffer gets paged out
        //
        // A more typical approach would be to allocate the memory using AERT_Allocate, which locks the memory
        // But for the purposes of this APO, CoTaskMemAlloc suffices, and the risk of glitches is not important
        m_pf32DelayBuffer.Allocate(GetSamplesPerFrame() * m_nDelayFrames);
        WriteSilence(m_pf32DelayBuffer, m_nDelayFrames, GetSamplesPerFrame());
        if (nullptr == m_pf32DelayBuffer)
        {
            hr = E_OUTOFMEMORY;
            goto Exit;
        }
    }
    
Exit:
    return hr;
}
Пример #3
0
BOOL AudioStream::ServiceBuffer (void)
{
	long	vol;
	int	fRtn = TRUE;

	if ( status != ASF_USED )
		return FALSE;

	EnterCriticalSection(&write_lock);

	// status may have changed, so lets check once again
	if ( status != ASF_USED ){
		LeaveCriticalSection(&write_lock);
		return FALSE;
	}

	// Check for reentrance
	if (InterlockedExchange (&m_lInService, TRUE) == FALSE) {
		if ( m_bFade == TRUE ) {
			if ( m_lCutoffVolume == -10000 ) {
				vol = Get_Volume();
//				nprintf(("Alan","Volume is: %d\n",vol));
				m_lCutoffVolume = max(vol - VOLUME_ATTENUATION_BEFORE_CUTOFF, -10000);
			}

			vol = Get_Volume();
			vol = vol - FADE_VOLUME_INTERVAL;	// decrease by 1db
//			nprintf(("Alan","Volume is now: %d\n",vol));
			Set_Volume(vol);

//			nprintf(("Sound","SOUND => Volume for stream sound is %d\n",vol));
//			nprintf(("Alan","Cuttoff Volume is: %d\n",m_lCutoffVolume));
			if ( vol < m_lCutoffVolume ) {
				m_bFade = 0;
				m_lCutoffVolume = -10000;
				if ( m_bDestroy_when_faded == TRUE ) {
					LeaveCriticalSection(&write_lock);
					Destroy();	
					// Reset reentrancy semaphore
					InterlockedExchange (&m_lInService, FALSE);
					return FALSE;
				}
				else {
					Stop_and_Rewind();
					// Reset reentrancy semaphore
					LeaveCriticalSection(&write_lock);
					InterlockedExchange (&m_lInService, FALSE);
					return TRUE;
				}
			}
		}

		// All of sound not played yet, send more data to buffer
		DWORD dwFreeSpace = GetMaxWriteSize ();

		// Determine free space in sound buffer
		if (dwFreeSpace) {

			// Some wave data remains, but not enough to fill free space
			// Send wave data to buffer, fill remainder of free space with silence
			uint num_bytes_written;

			if (WriteWaveData (dwFreeSpace, &num_bytes_written) == SUCCESS) {
//				nprintf(("Alan","Num bytes written: %d\n", num_bytes_written));

				if ( m_pwavefile->m_total_uncompressed_bytes_read >= m_pwavefile->m_max_uncompressed_bytes_to_read ) {
					m_fade_timer_id = timer_get_milliseconds() + 1700;		// start fading 1.7 seconds from now
					m_finished_id = timer_get_milliseconds() + 2000;		// 2 seconds left to play out buffer
					m_pwavefile->m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
				}

				if ( (m_fade_timer_id>0) && ((uint)timer_get_milliseconds() > m_fade_timer_id) ) {
					m_fade_timer_id = 0;
					Fade_and_Stop();
				}

				if ( (m_finished_id>0) && ((uint)timer_get_milliseconds() > m_finished_id) ) {
					m_finished_id = 0;
					m_bPastLimit = TRUE;
				}

				if ( (num_bytes_written < dwFreeSpace) && m_bReadingDone ) {
					int num_bytes_silence;
					num_bytes_silence = dwFreeSpace - num_bytes_written;

					if ( num_bytes_silence > 0 ) {

						m_silence_written += num_bytes_silence;
						if (WriteSilence (num_bytes_silence) == FAILURE)	{
							fRtn = FALSE;
							Int3();
						}

						if ( m_silence_written >= m_cbBufSize ) {
							m_silence_written = 0;

							if ( m_bDestroy_when_faded == TRUE ) {
								LeaveCriticalSection(&write_lock);
								Destroy();
								// Reset reentrancy semaphore
								InterlockedExchange (&m_lInService, FALSE);
								return FALSE;
							}

							// All of sound has played, stop playback or loop again
							if ( m_bLooping && !m_bFade) {
								Play(m_lVolume, m_bLooping);
							}
							else {
								Stop_and_Rewind();
							}
						}
					}
				}
			}
			else {
				// Error writing wave data
				fRtn = FALSE;
				Int3(); 
			}
		}

        // Reset reentrancy semaphore
        InterlockedExchange (&m_lInService, FALSE);
    } else {
		// Service routine reentered. Do nothing, just return
		fRtn = FALSE;
    }

	LeaveCriticalSection(&write_lock);
	return (fRtn);
}
Пример #4
0
//-------------------------------------------------------------------------
// Description:
//
//  Do the actual processing of data.
//
// Parameters:
//
//      u32NumInputConnections      - [in] number of input connections
//      ppInputConnections          - [in] pointer to list of input APO_CONNECTION_PROPERTY pointers
//      u32NumOutputConnections      - [in] number of output connections
//      ppOutputConnections         - [in] pointer to list of output APO_CONNECTION_PROPERTY pointers
//
// Return values:
//
//      void
//
// Remarks:
//
//  This function processes data in a manner dependent on the implementing
//  object.  This routine can not fail and can not block, or call any other
//  routine that blocks, or touch pagable memory.
//
STDMETHODIMP_(void) CSwapAPOMFX::APOProcess(
    UINT32 u32NumInputConnections,
    APO_CONNECTION_PROPERTY** ppInputConnections,
    UINT32 u32NumOutputConnections,
    APO_CONNECTION_PROPERTY** ppOutputConnections)
{
    UNREFERENCED_PARAMETER(u32NumInputConnections);
    UNREFERENCED_PARAMETER(u32NumOutputConnections);

    FLOAT32 *pf32InputFrames, *pf32OutputFrames;

    ATLASSERT(m_bIsLocked);

    // assert that the number of input and output connectins fits our registration properties
    ATLASSERT(m_pRegProperties->u32MinInputConnections <= u32NumInputConnections);
    ATLASSERT(m_pRegProperties->u32MaxInputConnections >= u32NumInputConnections);
    ATLASSERT(m_pRegProperties->u32MinOutputConnections <= u32NumOutputConnections);
    ATLASSERT(m_pRegProperties->u32MaxOutputConnections >= u32NumOutputConnections);

    // check APO_BUFFER_FLAGS.
    switch( ppInputConnections[0]->u32BufferFlags )
    {
        case BUFFER_INVALID:
        {
            ATLASSERT(false);  // invalid flag - should never occur.  don't do anything.
            break;
        }
        case BUFFER_VALID:
        case BUFFER_SILENT:
        {
            // get input pointer to connection buffer
            pf32InputFrames = reinterpret_cast<FLOAT32*>(ppInputConnections[0]->pBuffer);
            ATLASSERT( IS_VALID_TYPED_READ_POINTER(pf32InputFrames) );

            // get output pointer to connection buffer
            pf32OutputFrames = reinterpret_cast<FLOAT32*>(ppOutputConnections[0]->pBuffer);
            ATLASSERT( IS_VALID_TYPED_READ_POINTER(pf32OutputFrames) );

            if (BUFFER_SILENT == ppInputConnections[0]->u32BufferFlags)
            {
                WriteSilence( pf32InputFrames,
                              ppInputConnections[0]->u32ValidFrameCount,
                              GetSamplesPerFrame() );
            }

            // swap and apply coefficients to the input buffer in-place
            if (
                !IsEqualGUID(m_AudioProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW) &&
                m_fEnableSwapMFX &&
                (1 < m_u32SamplesPerFrame)
            )
            {
                ProcessSwapScale(pf32InputFrames, pf32InputFrames,
                            ppInputConnections[0]->u32ValidFrameCount,
                            m_u32SamplesPerFrame, m_pf32Coefficients );
            }
            
            // copy to the delay buffer
            if (
                !IsEqualGUID(m_AudioProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW) &&
                m_fEnableDelayMFX
            )
            {
                ProcessDelay(pf32OutputFrames, pf32InputFrames,
                             ppInputConnections[0]->u32ValidFrameCount,
                             GetSamplesPerFrame(),
                             m_pf32DelayBuffer,
                             m_nDelayFrames,
                             &m_iDelayIndex);

                // we don't try to remember silence
                ppOutputConnections[0]->u32BufferFlags = BUFFER_VALID;
            }
            else
            {
                // copy the memory only if there is an output connection, and input/output pointers are unequal
                if ( (0 != u32NumOutputConnections) &&
                      (ppOutputConnections[0]->pBuffer != ppInputConnections[0]->pBuffer) )
                {
                    CopyFrames( pf32OutputFrames, pf32InputFrames,
                                ppInputConnections[0]->u32ValidFrameCount,
                                GetSamplesPerFrame() );
                }
                
                // pass along buffer flags
                ppOutputConnections[0]->u32BufferFlags = ppInputConnections[0]->u32BufferFlags;
            }

            // Set the valid frame count.
            ppOutputConnections[0]->u32ValidFrameCount = ppInputConnections[0]->u32ValidFrameCount;

            break;
        }
        default:
        {
            ATLASSERT(false);  // invalid flag - should never occur
            break;
        }
    } // switch

} // APOProcess