Пример #1
0
/// Thread entry point, called by wxWidgets.
/// @return Always 0.
wxThread::ExitCode Controller::Entry()
{
	mCommand = NONE;
	//assumes mutex already locked here, so we can signal to the main thread that we are ready to accept signals by unlocking it when Wait() is called
	while (1) {
		if (NONE == mCommand) { //not been told to do anything new during previous interation
			mCondition->Wait(); //unlock mutex and wait for a signal, then relock
		}
		//Now we're going
		ControllerThreadEvent event(wxEVT_CONTROLLER_THREAD);
		event.SetName(mName);
		event.SetCommand(mCommand);
		mCommand = NONE; //can now detect if another command is issued while busy(more frequently during abnormal situations) 
		mMutex.Unlock();
		if (DIE == event.GetCommand()) {
			AddPendingEvent(event);
			break;
		}
		//do the work...
		ProdAuto::Recorder::ReturnCode rc = ProdAuto::Recorder::SUCCESS;
		wxString msg;
		CORBA::StringSeq_var strings; //deletes itself
		ProdAuto::MxfTimecode timecode; //structure so deletes itself
		//send a recorder command, if any
		for (int i = 0; i < 2; i++) { //always good to try things twice with CORBA
			event.SetResult(SUCCESS); //default
			switch (event.GetCommand())
			{
				case CONNECT: case RECONNECT: {
//std::cerr << "thread CONNECT/RECONNECT" << std::endl;
					ProdAuto::MxfDuration maxPreroll = InvalidMxfDuration; //initialisation prevents compiler warning
					ProdAuto::MxfDuration maxPostroll = InvalidMxfDuration; //initialisation prevents compiler warning
					ProdAuto::TrackList_var trackList;
					bool routerRecorder = false; //initialisation prevents compiler warning
					event.SetTimecodeStateChanged(); //always trigger action
					mLastTimecodeReceived.undefined = true; //guarantee that a valid timecode will be assumed to be running timecode
					mMutex.Lock();
					wxString name = mName;
					mMutex.Unlock();
					msg = mComms->SelectRecorder(name, mRecorder);
					if (msg.IsEmpty()) { //OK so far
						try {
							trackList = mRecorder->Tracks();
							maxPreroll = mRecorder->MaxPreRoll();
							maxPostroll = mRecorder->MaxPostRoll();
							event.SetTrackStatusList(mRecorder->TracksStatus());
							routerRecorder = wxString(mRecorder->RecordingFormat(), *wxConvCurrent).MakeUpper().Matches(wxT("*ROUTER*"));
							strings = mRecorder->ProjectNames();
						}
						catch (const CORBA::Exception & e) {
//std::cerr << "connect/reconnect exception: " << e._name() << std::endl;
							msg = wxT("Error communicating with this recorder: ") + wxString(e._name(), *wxConvCurrent) + wxT(".  Is it operational and connected to the network?  The problem may resolve itself if you try again.");
						}
					}
					if (!msg.IsEmpty()) { //failed to select
						event.SetResult(COMM_FAILURE);
					}
					else { //OK so far
						mMutex.Lock();
						if (CONNECT == event.GetCommand()) {
							//various checks on the data we've acquired
							if (!trackList->length() || !event.GetNTracks()) {
								msg = wxT("This recorder has no tracks.");
							}
							else if (maxPreroll.undefined) {
								msg = wxT("This recorder has no maximum preroll.");
							}
							else if (!maxPreroll.edit_rate.numerator || !maxPreroll.edit_rate.denominator) {
								msg = wxT("This recorder has invalid maximum preroll."); //don't want divide by zero errors
							}
							else if (maxPostroll.undefined) { //quite likely as postroll isn't dependent on buffer length
								mMaxPostroll = maxPreroll; //for the edit rate values
								mMaxPostroll.undefined = false;
								mMaxPostroll.samples = DEFAULT_MAX_POSTROLL;
							}
							else if (!maxPostroll.edit_rate.numerator || !maxPostroll.edit_rate.denominator) {
								msg = wxT("This recorder has invalid maximum postroll."); //don't want divide by zero errors
							}
							else {
								mMaxPostroll = maxPostroll;
							}
							mTrackList = trackList;
							mMaxPreroll = maxPreroll;
							mSourceList.length(mTrackList->length());
							mRouterRecorder = routerRecorder;
						}
						else { //reconnecting
							//check nothing's changed after reconnection
							if (maxPreroll.undefined
							 || maxPreroll.edit_rate.numerator != mMaxPreroll.edit_rate.numerator
							 || maxPreroll.edit_rate.denominator != mMaxPreroll.edit_rate.denominator
							 || maxPreroll.samples != mMaxPreroll.samples) {
								msg = wxT("the maximum preroll has changed");
							}
							else if ((maxPostroll.undefined && mMaxPostroll.samples != DEFAULT_MAX_POSTROLL) ||
							 (!maxPostroll.undefined &&
							  (maxPostroll.edit_rate.numerator != mMaxPostroll.edit_rate.numerator
							  || maxPostroll.edit_rate.denominator != mMaxPostroll.edit_rate.denominator
							  || maxPostroll.samples != mMaxPostroll.samples))) {
								msg = wxT("the maximum postroll has changed");
							}
							else if (trackList->length() != mTrackList->length()) {
								msg = wxT("the number of tracks has changed");
							}
							else if (mRouterRecorder && !routerRecorder) {
								msg = wxT("it is no longer a router recorder");
							}
							else if (!mRouterRecorder && routerRecorder) {
								msg = wxT("it now presents itself as a router recorder");
							}
							else {
								for (unsigned int i = 0; i < trackList->length(); i++) {
									if (strcmp(trackList[i].name, mTrackList[i].name)) {
										msg = wxT("name");
									}
									else if (trackList[i].type != mTrackList[i].type) {
										msg = wxT("type");
									}
									else if (trackList[i].id != mTrackList[i].id) {
										msg = wxT("ID");
									}
									else if (trackList[i].has_source != mTrackList[i].has_source) {
										msg = wxT("\"has_source\" status");
									}
									else if (trackList[i].has_source && strcmp(trackList[i].src.package_name, mTrackList[i].src.package_name)) {
										msg = wxT("package name");
									}
									else if (trackList[i].has_source && strcmp(trackList[i].src.track_name, mTrackList[i].src.track_name)) {
										msg = wxT("track name");
									}
									if (msg.Length()) {
										msg = wxT("track \"") + wxString(mTrackList[i].name, *wxConvCurrent) + wxT("\" has changed ") + msg;
										break;
									}
								}
							}
						}
						mMutex.Unlock();
					}
					if (msg.IsEmpty()) {
						rc = ProdAuto::Recorder::SUCCESS;
					}
					else {
						rc = ProdAuto::Recorder::FAILURE;
						event.SetMessage(msg);
						event.SetTrackStatusList(0); //track status not valid
					}
					break;
				}
				case SET_TAPE_IDS: {
//std::cerr << "thread SET_TAPE_IDS" << std::endl;
					mMutex.Lock();
					CORBA::StringSeq sourceNames = mSourceNames;
					CORBA::StringSeq tapeIds = mTapeIds;
					mMutex.Unlock();
					try {
						mRecorder->SetTapeNames(sourceNames, tapeIds);
					}
					catch (const CORBA::Exception & e) {
//std::cerr << "set tape IDs exception: " << e._name() << std::endl;
						event.SetResult(COMM_FAILURE);
					}
					rc = ProdAuto::Recorder::SUCCESS; //no return code suppled by SetTapeNames()
					break;
				}
				case ADD_PROJECT_NAMES: {
					mMutex.Lock();
					CORBA::StringSeq projectNames = mProjectNames;
					mMutex.Unlock();
					try {
						mRecorder->AddProjectNames(projectNames);
					}
					catch (const CORBA::Exception & e) {
//std::cerr << "AddProjectNames exception: " << e._name() << std::endl;
						event.SetResult(COMM_FAILURE);
					}
					rc = ProdAuto::Recorder::SUCCESS; //no return code suppled by AddProject()
					break;
				}
				case RECORD: {
//std::cerr << "thread RECORD" << std::endl;
					mMutex.Lock();
					timecode = mStartTimecode;
					ProdAuto::MxfDuration preroll = mPreroll;
					CORBA::BooleanSeq rec_enable = mEnableList;
					std::string project = (const char *) mProject.mb_str(*wxConvCurrent);
					mMutex.Unlock();
					try {
						rc = mRecorder->Start(timecode, preroll, rec_enable, project.c_str(), false);
					}
					catch (const CORBA::Exception & e) {
//std::cerr << "start exception: " << e._name() << std::endl;
						event.SetResult(COMM_FAILURE);
					}
					break;
				}
				case STOP: {
//std::cerr << "thread STOP" << std::endl;
					mMutex.Lock();
					timecode = mStopTimecode;
					ProdAuto::MxfDuration postroll = mPostroll;
					char * description = CORBA::string_dup(mDescription.mb_str(*wxConvCurrent));
					ProdAuto::LocatorSeq locators = mLocators; 
					mMutex.Unlock();
					try {
						rc = mRecorder->Stop(timecode, postroll, description, locators, strings.out());
					}
					catch (const CORBA::Exception & e) {
//std::cerr << "stop exception: " << e._name() << std::endl;
						event.SetResult(COMM_FAILURE);
					}
					event.SetTimecodeStateChanged(); //so that a timecode that was stuck during the recording will be reported as such
					break;
				}
				default:
					break;
			}
			if (COMM_FAILURE != event.GetResult()) {
				if (ProdAuto::Recorder::SUCCESS == rc) {
					event.SetStrings(strings); //only relevant for STOP (list of files) and CONNECT (list of project names)
					if (!timecode.edit_rate.numerator || !timecode.edit_rate.denominator) {
						timecode.undefined = true;
					}
					event.SetTimecode(timecode); //only relevant for START and STOP
				}
				else {
					event.SetResult(FAILURE);
				}
				break; //comms successful or no call made: no need to try again
			}
		}
		event.SetTrackList(mTrackList);
		//get status
		if (COMM_FAILURE != event.GetResult()) {
			for (int j = 0; j < 2; j++) { //always good to try things twice with CORBA
				try {
					if (CONNECT != event.GetCommand() && RECONNECT != event.GetCommand()) { //haven't already got track status list
						event.SetTrackStatusList(mRecorder->TracksStatus());
					}
					//timecode situation
					if (!event.GetNTracks() || event.GetTrackStatusList()[0].timecode.undefined || !event.GetTrackStatusList()[0].timecode.edit_rate.numerator || !event.GetTrackStatusList()[0].timecode.edit_rate.denominator) { //no or invalid timecode
						if (!mLastTimecodeReceived.undefined) { //newly in this state
							mLastTimecodeReceived.undefined = true; //to allow future detection of state change
							event.SetTimecodeStateChanged();
							//ABSENT is the default timecode state in the event
						}
					}
					else { //timecode value is OK
						ProdAuto::MxfTimecode timecode = event.GetTrackStatusList()[0].timecode;
						if (mLastTimecodeReceived.undefined) { //timecode has just appeared
							event.SetTimecodeState(UNCONFIRMED);
							if (!mTimecodeRunning) { //just started
								mTimecodeRunning = true; //to allow future detection of state change
								event.SetTimecodeStateChanged();
							}
						}
						else if (!wxDateTime::Now().IsEqualUpTo(mLastTimecodeRequest, wxTimeSpan::Milliseconds(100))) { //long enough since the last stored value was received to assume that the timecode has changed
							if (timecode.samples != mLastTimecodeReceived.samples) { //timecode is running
								event.SetTimecodeState(RUNNING);
								if (!mTimecodeRunning) { //just started
									mTimecodeRunning = true; //to allow future detection of state change
									event.SetTimecodeStateChanged();
								}
							}
							else { //timecode is stuck
								event.SetTimecodeState(STUCK);
								if (mTimecodeRunning) { //just stopped
									mTimecodeRunning = false; //to allow future detection of state change
									event.SetTimecodeStateChanged();
								}
							}
						}
						else {
							//repeat previous status
							event.SetTimecodeState(mTimecodeRunning ? UNCONFIRMED : STUCK);
						}
						mLastTimecodeReceived = timecode;
						mLastTimecodeRequest = wxDateTime::Now(); //now or sometime before!
					}
					break; //successful: no need to try again
				}
				catch (const CORBA::Exception & e) {
//std::cerr << "status exception: " << e._name() << std::endl;
					event.SetResult(COMM_FAILURE);
				//indicated by list size being zero
				}
			}
		}
		//communicate the results
		AddPendingEvent(event);
		mMutex.Lock();
	}
	return 0;
}
Пример #2
0
RecordingDevice::ReturnCode RecordingDevice::StopRecording(const Timecode & tc)
{
    bool ok_so_far = true;
    ReturnCode return_code = OK;

    if(CORBA::is_nil(mRecorder))
    {
        ok_so_far = false;
        return_code = NO_DEVICE;
    }

    if (ok_so_far)
    {
        // Sort out parameters to be passed
        ProdAuto::MxfTimecode stop_tc_mxf;
        stop_tc_mxf.undefined = false;
        stop_tc_mxf.samples = tc.FramesSinceMidnight();

        //::Duration post_roll_dur;
        //post_roll_dur.TotalFrames(post_roll_frames);
        ProdAuto::MxfDuration post_roll_mxf;
        post_roll_mxf.undefined = false;
        post_roll_mxf.samples = post_roll_frames;


        ::ProdAuto::Recorder::ReturnCode result;
        CORBA::StringSeq_var files;
        ::ProdAuto::LocatorSeq locators;
        try
        {
            result = mRecorder->Stop(stop_tc_mxf, post_roll_mxf, "", "", locators, files.out());
        }
        catch (const CORBA::Exception &)
        {
            result = ProdAuto::Recorder::FAILURE;
        }

        if(ProdAuto::Recorder::SUCCESS == result)
        {
            //stop_tc += post_roll_dur;
            //mOutTime = stop_tc.Text(); // store the stop timecode

            //::Duration dur_tc;
            //dur_tc = Timecode(mOutTime.c_str()) - Timecode(mInTime.c_str());
            //mDuration = dur_tc.Text(); // store the duration

            // need to store paths
            //for(int i = 0; i < SDI_RECORDER_CHANNELS; ++i)
            //{
                //mFilename[i] = path.in()[i].in();
            //}

            mIsRecording = false;
            mHasRecorded = true;
        }
        else
        {
            ok_so_far = false;
            return_code = FAILED;
        }
    }

    return return_code;
}