//------------------------------------------------------------------- // Name: ValidStateMatrix // Description: Class-static matrix of operations vs states. // // If an entry is TRUE, the operation is valid from that state. //------------------------------------------------------------------- bool ValidStateMatrix(State stat, CAsyncOperation.StreamOperation so) { if (m_ValidStateMatrix == null) { m_ValidStateMatrix = new bool[(int)State.Count, (int)CAsyncOperation.StreamOperation.Op_Count]; // Note about states: // 1. OnClockRestart should only be called from paused state. // 2. While paused, the sink accepts samples but does not process them. m_ValidStateMatrix[(int)State.TypeNotSet, (int)CAsyncOperation.StreamOperation.OpSetMediaType] = true; m_ValidStateMatrix[(int)State.TypeNotSet, (int)CAsyncOperation.StreamOperation.OpStart] = false; m_ValidStateMatrix[(int)State.TypeNotSet, (int)CAsyncOperation.StreamOperation.OpRestart] = false; m_ValidStateMatrix[(int)State.TypeNotSet, (int)CAsyncOperation.StreamOperation.OpPause] = false; m_ValidStateMatrix[(int)State.TypeNotSet, (int)CAsyncOperation.StreamOperation.OpStop] = false; m_ValidStateMatrix[(int)State.TypeNotSet, (int)CAsyncOperation.StreamOperation.OpProcessSample] = false; m_ValidStateMatrix[(int)State.TypeNotSet, (int)CAsyncOperation.StreamOperation.OpPlaceMarker] = false; m_ValidStateMatrix[(int)State.TypeNotSet, (int)CAsyncOperation.StreamOperation.OpFinalize] = false; m_ValidStateMatrix[(int)State.Ready, (int)CAsyncOperation.StreamOperation.OpSetMediaType] = true; m_ValidStateMatrix[(int)State.Ready, (int)CAsyncOperation.StreamOperation.OpStart] = true; m_ValidStateMatrix[(int)State.Ready, (int)CAsyncOperation.StreamOperation.OpRestart] = false; m_ValidStateMatrix[(int)State.Ready, (int)CAsyncOperation.StreamOperation.OpPause] = true; m_ValidStateMatrix[(int)State.Ready, (int)CAsyncOperation.StreamOperation.OpStop] = true; m_ValidStateMatrix[(int)State.Ready, (int)CAsyncOperation.StreamOperation.OpProcessSample] = false; m_ValidStateMatrix[(int)State.Ready, (int)CAsyncOperation.StreamOperation.OpPlaceMarker] = true; m_ValidStateMatrix[(int)State.Ready, (int)CAsyncOperation.StreamOperation.OpFinalize] = true; m_ValidStateMatrix[(int)State.Started, (int)CAsyncOperation.StreamOperation.OpSetMediaType] = false; m_ValidStateMatrix[(int)State.Started, (int)CAsyncOperation.StreamOperation.OpStart] = true; m_ValidStateMatrix[(int)State.Started, (int)CAsyncOperation.StreamOperation.OpRestart] = false; m_ValidStateMatrix[(int)State.Started, (int)CAsyncOperation.StreamOperation.OpPause] = true; m_ValidStateMatrix[(int)State.Started, (int)CAsyncOperation.StreamOperation.OpStop] = true; m_ValidStateMatrix[(int)State.Started, (int)CAsyncOperation.StreamOperation.OpProcessSample] = true; m_ValidStateMatrix[(int)State.Started, (int)CAsyncOperation.StreamOperation.OpPlaceMarker] = true; m_ValidStateMatrix[(int)State.Started, (int)CAsyncOperation.StreamOperation.OpFinalize] = true; m_ValidStateMatrix[(int)State.Paused, (int)CAsyncOperation.StreamOperation.OpSetMediaType] = false; m_ValidStateMatrix[(int)State.Paused, (int)CAsyncOperation.StreamOperation.OpStart] = true; m_ValidStateMatrix[(int)State.Paused, (int)CAsyncOperation.StreamOperation.OpRestart] = true; m_ValidStateMatrix[(int)State.Paused, (int)CAsyncOperation.StreamOperation.OpPause] = true; m_ValidStateMatrix[(int)State.Paused, (int)CAsyncOperation.StreamOperation.OpStop] = true; m_ValidStateMatrix[(int)State.Paused, (int)CAsyncOperation.StreamOperation.OpProcessSample] = true; m_ValidStateMatrix[(int)State.Paused, (int)CAsyncOperation.StreamOperation.OpPlaceMarker] = true; m_ValidStateMatrix[(int)State.Paused, (int)CAsyncOperation.StreamOperation.OpFinalize] = true; m_ValidStateMatrix[(int)State.Stopped, (int)CAsyncOperation.StreamOperation.OpSetMediaType] = false; m_ValidStateMatrix[(int)State.Stopped, (int)CAsyncOperation.StreamOperation.OpStart] = true; m_ValidStateMatrix[(int)State.Stopped, (int)CAsyncOperation.StreamOperation.OpRestart] = false; m_ValidStateMatrix[(int)State.Stopped, (int)CAsyncOperation.StreamOperation.OpPause] = false; m_ValidStateMatrix[(int)State.Stopped, (int)CAsyncOperation.StreamOperation.OpStop] = true; m_ValidStateMatrix[(int)State.Stopped, (int)CAsyncOperation.StreamOperation.OpProcessSample] = false; m_ValidStateMatrix[(int)State.Stopped, (int)CAsyncOperation.StreamOperation.OpPlaceMarker] = true; m_ValidStateMatrix[(int)State.Stopped, (int)CAsyncOperation.StreamOperation.OpFinalize] = true; m_ValidStateMatrix[(int)State.Finalized, (int)CAsyncOperation.StreamOperation.OpSetMediaType] = false; m_ValidStateMatrix[(int)State.Finalized, (int)CAsyncOperation.StreamOperation.OpStart] = false; m_ValidStateMatrix[(int)State.Finalized, (int)CAsyncOperation.StreamOperation.OpRestart] = false; m_ValidStateMatrix[(int)State.Finalized, (int)CAsyncOperation.StreamOperation.OpPause] = false; m_ValidStateMatrix[(int)State.Finalized, (int)CAsyncOperation.StreamOperation.OpStop] = false; m_ValidStateMatrix[(int)State.Finalized, (int)CAsyncOperation.StreamOperation.OpProcessSample] = false; m_ValidStateMatrix[(int)State.Finalized, (int)CAsyncOperation.StreamOperation.OpPlaceMarker] = false; m_ValidStateMatrix[(int)State.Finalized, (int)CAsyncOperation.StreamOperation.OpFinalize] = false; } return m_ValidStateMatrix[(int)stat, (int)so]; }
//------------------------------------------------------------------- // Name: ValidateOperation // Description: Checks if an operation is valid in the current state. //------------------------------------------------------------------- void ValidateOperation(CAsyncOperation.StreamOperation op) { Debug.Assert(!m_IsShutdown); bool bTransitionAllowed = ValidStateMatrix(m_state, op); if (!bTransitionAllowed) { throw new COMException("Not valid from current state", MFError.MF_E_INVALIDREQUEST); } }
//------------------------------------------------------------------- // Name: DispatchProcessSample // Description: Complete a ProcessSample or PlaceMarker request. //------------------------------------------------------------------- void DispatchProcessSample(CAsyncOperation pOp) { Debug.Assert(pOp != null); try { ProcessSamplesFromQueue(FlushState.WriteSamples); // Ask for another sample if (pOp.m_op == CAsyncOperation.StreamOperation.OpProcessSample) { QueueEvent(MediaEventType.MEStreamSinkRequestSample, Guid.Empty, 0, null); } } catch (Exception e) { int hr = Marshal.GetHRForException(e); // We are in the middle of an asynchronous operation, so if something failed, send an error. QueueEvent(MediaEventType.MEError, Guid.Empty, hr, null); } }
//------------------------------------------------------------------- // Name: QueueAsyncOperation // Description: Puts an async operation on the work queue. //------------------------------------------------------------------- void QueueAsyncOperation(CAsyncOperation.StreamOperation op) { int hr; CAsyncOperation pOp = new CAsyncOperation(op); // Created with ref count = 1 hr = MFExtern.MFPutWorkItem(m_WorkQueueId, this, pOp); MFError.ThrowExceptionForHR(hr); //SAFE_RELEASE(pOp); }
//------------------------------------------------------------------- // Name: DispatchFinalize // Description: Complete a BeginFinalize request. //------------------------------------------------------------------- void DispatchFinalize(CAsyncOperation pOp) { int hr; int cbSize = 0; int cbWritten = 0; try { WAV_FILE_HEADER header = new WAV_FILE_HEADER(); int cbFileSize = m_cbDataWritten + Marshal.SizeOf(typeof(WAV_FILE_HEADER)) - Marshal.SizeOf(typeof(RIFFCHUNK)); // Write any samples left in the queue... ProcessSamplesFromQueue(FlushState.WriteSamples); // Now we're done writing all of the audio data. // Fill in the RIFF headers... hr = MFExtern.MFCreateWaveFormatExFromMFMediaType(m_pCurrentType, out header.WaveFormat, out cbSize, MFWaveFormatExConvertFlags.Normal); MFError.ThrowExceptionForHR(hr); header.FileHeader = new RIFFCHUNK(); header.FileHeader.fcc = new FourCC('R', 'I', 'F', 'F'); header.FileHeader.cb = cbFileSize; header.fccWaveType = new FourCC('W', 'A', 'V', 'E'); header.WaveHeader = new RIFFCHUNK(); header.WaveHeader.fcc = new FourCC('f', 'm', 't', ' '); header.WaveHeader.cb = Marshal.SizeOf(typeof(WaveFormatEx)); header.DataHeader = new RIFFCHUNK(); header.DataHeader.fcc = new FourCC('d', 'a', 't', 'a'); header.DataHeader.cb = m_cbDataWritten; // Move the file pointer back to the start of the file and write the // RIFF headers. hr = m_pByteStream.SetCurrentPosition(0); MFError.ThrowExceptionForHR(hr); IntPtr ip = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(WAV_FILE_HEADER))); try { Marshal.StructureToPtr(header, ip, false); hr = m_pByteStream.Write(ip, Marshal.SizeOf(typeof(WAV_FILE_HEADER)), out cbWritten); MFError.ThrowExceptionForHR(hr); } finally { Marshal.FreeCoTaskMem(ip); } // Close the byte stream. hr = m_pByteStream.Close(); MFError.ThrowExceptionForHR(hr); hr = 0; } catch (Exception e) { hr = Marshal.GetHRForException(e); } // Set the async status and invoke the callback. hr = m_pFinalizeResult.SetStatus(hr); MFError.ThrowExceptionForHR(hr); hr = MFExtern.MFInvokeCallback(m_pFinalizeResult); MFError.ThrowExceptionForHR(hr); }