// timeout in milliseconds OMX_BUFFERHEADERTYPE* Component::getInputBuffer(long timeout) { if(!handle) { ofLogError(__func__) << getName() << " NO HANDLE"; } OMX_BUFFERHEADERTYPE *omx_input_buffer = NULL; pthread_mutex_lock(&m_omx_input_mutex); struct timespec endtime; clock_gettime(CLOCK_REALTIME, &endtime); add_timespecs(endtime, timeout); while (1 && !doFlushInput) { if(!inputBuffersAvailable.empty()) { omx_input_buffer = inputBuffersAvailable.front(); inputBuffersAvailable.pop(); break; } int retcode = pthread_cond_timedwait(&m_input_buffer_cond, &m_omx_input_mutex, &endtime); if (retcode != 0) { ofLogError(__func__) << componentName << " TIMEOUT"; break; } } pthread_mutex_unlock(&m_omx_input_mutex); return omx_input_buffer; }
// timeout in milliseconds OMX_BUFFERHEADERTYPE *COMXCoreComponent::GetInputBuffer(long timeout) { OMX_BUFFERHEADERTYPE *omx_input_buffer = NULL; if(!m_handle) return NULL; pthread_mutex_lock(&m_omx_input_mutex); struct timespec endtime; clock_gettime(CLOCK_REALTIME, &endtime); add_timespecs(endtime, timeout); while (1 && !m_flush_input) { if(!m_omx_input_avaliable.empty()) { omx_input_buffer = m_omx_input_avaliable.front(); m_omx_input_avaliable.pop(); break; } int retcode = pthread_cond_timedwait(&m_input_buffer_cond, &m_omx_input_mutex, &endtime); if (retcode != 0) { CLog::Log(LOGERROR, "COMXCoreComponent::GetInputBuffer %s wait event timeout\n", m_componentName.c_str()); break; } } pthread_mutex_unlock(&m_omx_input_mutex); return omx_input_buffer; }
// timeout in milliseconds OMX_ERRORTYPE COMXCoreComponent::WaitForCommand(OMX_U32 command, OMX_U32 nData2, long timeout) { #ifdef OMX_DEBUG_EVENTS Logger::LogOut(LOG_LEVEL_DEBUG, "COMXCoreComponent::WaitForCommand %s wait event.eEvent 0x%08x event.command 0x%08x event.nData2 %d", m_componentName.c_str(), (int)OMX_EventCmdComplete, (int)command, (int)nData2); #endif pthread_mutex_lock(&m_omx_event_mutex); struct timespec endtime; clock_gettime(CLOCK_REALTIME, &endtime); add_timespecs(endtime, timeout); while(true) { for (std::vector<omx_event>::iterator it = m_omx_events.begin(); it != m_omx_events.end(); it++) { omx_event event = *it; #ifdef OMX_DEBUG_EVENTS Logger::LogOut(LOG_LEVEL_DEBUG, "COMXCoreComponent::WaitForCommand %s inlist event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 %d", m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2); #endif if(event.eEvent == OMX_EventError && event.nData1 == (OMX_U32)OMX_ErrorSameState && event.nData2 == 1) { #ifdef OMX_DEBUG_EVENTS Logger::LogOut(LOG_LEVEL_DEBUG, "COMXCoreComponent::WaitForCommand %s remove event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 %d", m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2); #endif m_omx_events.erase(it); pthread_mutex_unlock(&m_omx_event_mutex); return OMX_ErrorNone; } else if(event.eEvent == OMX_EventError) { m_omx_events.erase(it); pthread_mutex_unlock(&m_omx_event_mutex); return (OMX_ERRORTYPE)event.nData1; } else if(event.eEvent == OMX_EventCmdComplete && event.nData1 == command && event.nData2 == nData2) { #ifdef OMX_DEBUG_EVENTS Logger::LogOut(LOG_LEVEL_DEBUG, "COMXCoreComponent::WaitForCommand %s remove event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 %d", m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2); #endif m_omx_events.erase(it); pthread_mutex_unlock(&m_omx_event_mutex); return OMX_ErrorNone; } } int retcode = pthread_cond_timedwait(&m_omx_event_cond, &m_omx_event_mutex, &endtime); if (retcode != 0) { Logger::LogOut(LOG_LEVEL_ERROR, "COMXCoreComponent::WaitForCommand %s wait timeout event.eEvent 0x%08x event.command 0x%08x event.nData2 %d", m_componentName.c_str(), (int)OMX_EventCmdComplete, (int)command, (int)nData2); pthread_mutex_unlock(&m_omx_event_mutex); return OMX_ErrorMax; } } pthread_mutex_unlock(&m_omx_event_mutex); return OMX_ErrorNone; }
// //========================================================================= // int main(int argc, char **argv) { int j; // Set sane defaults modesInitConfig(); // signal handlers: signal(SIGINT, sigintHandler); signal(SIGTERM, sigtermHandler); // Parse the command line options for (j = 1; j < argc; j++) { int more = j+1 < argc; // There are more arguments if (!strcmp(argv[j],"--device-index") && more) { Modes.dev_name = strdup(argv[++j]); } else if (!strcmp(argv[j],"--gain") && more) { Modes.gain = (int) (atof(argv[++j])*10); // Gain is in tens of DBs } else if (!strcmp(argv[j],"--enable-agc")) { Modes.enable_agc++; } else if (!strcmp(argv[j],"--freq") && more) { Modes.freq = (int) strtoll(argv[++j],NULL,10); } else if (!strcmp(argv[j],"--ifile") && more) { Modes.filename = strdup(argv[++j]); } else if (!strcmp(argv[j],"--iformat") && more) { ++j; if (!strcasecmp(argv[j], "uc8")) { Modes.input_format = INPUT_UC8; } else if (!strcasecmp(argv[j], "sc16")) { Modes.input_format = INPUT_SC16; } else if (!strcasecmp(argv[j], "sc16q11")) { Modes.input_format = INPUT_SC16Q11; } else { fprintf(stderr, "Input format '%s' not understood (supported values: UC8, SC16, SC16Q11)\n", argv[j]); exit(1); } } else if (!strcmp(argv[j],"--dcfilter")) { Modes.dc_filter = 1; } else if (!strcmp(argv[j],"--measure-noise")) { Modes.measure_noise = 1; } else if (!strcmp(argv[j],"--fix")) { Modes.nfix_crc = 1; } else if (!strcmp(argv[j],"--no-fix")) { Modes.nfix_crc = 0; } else if (!strcmp(argv[j],"--no-crc-check")) { Modes.check_crc = 0; } else if (!strcmp(argv[j],"--phase-enhance")) { Modes.phase_enhance = 1; } else if (!strcmp(argv[j],"--raw")) { Modes.raw = 1; } else if (!strcmp(argv[j],"--net")) { Modes.net = 1; } else if (!strcmp(argv[j],"--modeac")) { Modes.mode_ac = 1; } else if (!strcmp(argv[j],"--net-beast")) { Modes.beast = 1; } else if (!strcmp(argv[j],"--net-only")) { Modes.net = 1; Modes.net_only = 1; } else if (!strcmp(argv[j],"--net-heartbeat") && more) { Modes.net_heartbeat_interval = (uint64_t)(1000 * atof(argv[++j])); } else if (!strcmp(argv[j],"--net-ro-size") && more) { Modes.net_output_flush_size = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-ro-rate") && more) { Modes.net_output_flush_interval = 1000 * atoi(argv[++j]) / 15; // backwards compatibility } else if (!strcmp(argv[j],"--net-ro-interval") && more) { Modes.net_output_flush_interval = (uint64_t)(1000 * atof(argv[++j])); } else if (!strcmp(argv[j],"--net-ro-port") && more) { if (Modes.beast) // Required for legacy backward compatibility {Modes.net_output_beast_port = atoi(argv[++j]);;} else {Modes.net_output_raw_port = atoi(argv[++j]);} } else if (!strcmp(argv[j],"--net-ri-port") && more) { Modes.net_input_raw_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-bo-port") && more) { Modes.net_output_beast_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-bi-port") && more) { Modes.net_input_beast_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-bind-address") && more) { Modes.net_bind_address = strdup(argv[++j]); } else if (!strcmp(argv[j],"--net-http-port") && more) { Modes.net_http_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-fatsv-port") && more) { Modes.net_fatsv_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-sbs-port") && more) { Modes.net_output_sbs_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-buffer") && more) { Modes.net_sndbuf_size = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-verbatim")) { Modes.net_verbatim = 1; } else if (!strcmp(argv[j],"--forward-mlat")) { Modes.forward_mlat = 1; } else if (!strcmp(argv[j],"--onlyaddr")) { Modes.onlyaddr = 1; } else if (!strcmp(argv[j],"--metric")) { Modes.metric = 1; } else if (!strcmp(argv[j],"--aggressive")) { Modes.nfix_crc = MODES_MAX_BITERRORS; } else if (!strcmp(argv[j],"--interactive")) { Modes.interactive = Modes.throttle = 1; } else if (!strcmp(argv[j],"--throttle")) { Modes.throttle = 1; } else if (!strcmp(argv[j],"--interactive-rows") && more) { Modes.interactive_rows = atoi(argv[++j]); } else if (!strcmp(argv[j],"--interactive-ttl") && more) { Modes.interactive_display_ttl = (uint64_t)(1000 * atof(argv[++j])); } else if (!strcmp(argv[j],"--lat") && more) { Modes.fUserLat = atof(argv[++j]); } else if (!strcmp(argv[j],"--lon") && more) { Modes.fUserLon = atof(argv[++j]); } else if (!strcmp(argv[j],"--max-range") && more) { Modes.maxRange = atof(argv[++j]) * 1852.0; // convert to metres } else if (!strcmp(argv[j],"--debug") && more) { char *f = argv[++j]; while(*f) { switch(*f) { case 'D': Modes.debug |= MODES_DEBUG_DEMOD; break; case 'd': Modes.debug |= MODES_DEBUG_DEMODERR; break; case 'C': Modes.debug |= MODES_DEBUG_GOODCRC; break; case 'c': Modes.debug |= MODES_DEBUG_BADCRC; break; case 'p': Modes.debug |= MODES_DEBUG_NOPREAMBLE; break; case 'n': Modes.debug |= MODES_DEBUG_NET; break; case 'j': Modes.debug |= MODES_DEBUG_JS; break; default: fprintf(stderr, "Unknown debugging flag: %c\n", *f); exit(1); break; } f++; } } else if (!strcmp(argv[j],"--stats")) { if (!Modes.stats) Modes.stats = (uint64_t)1 << 60; // "never" } else if (!strcmp(argv[j],"--stats-range")) { Modes.stats_range_histo = 1; } else if (!strcmp(argv[j],"--stats-every") && more) { Modes.stats = (uint64_t) (1000 * atof(argv[++j])); } else if (!strcmp(argv[j],"--snip") && more) { snipMode(atoi(argv[++j])); exit(0); } else if (!strcmp(argv[j],"--help")) { showHelp(); exit(0); } else if (!strcmp(argv[j],"--ppm") && more) { Modes.ppm_error = atoi(argv[++j]); } else if (!strcmp(argv[j],"--quiet")) { Modes.quiet = 1; } else if (!strcmp(argv[j],"--show-only") && more) { Modes.show_only = (uint32_t) strtoul(argv[++j], NULL, 16); } else if (!strcmp(argv[j],"--mlat")) { Modes.mlat = 1; } else if (!strcmp(argv[j],"--interactive-rtl1090")) { Modes.interactive = 1; Modes.interactive_rtl1090 = 1; } else if (!strcmp(argv[j],"--oversample")) { Modes.oversample = 1; #ifndef _WIN32 } else if (!strcmp(argv[j], "--write-json") && more) { Modes.json_dir = strdup(argv[++j]); } else if (!strcmp(argv[j], "--write-json-every") && more) { Modes.json_interval = (uint64_t)(1000 * atof(argv[++j])); if (Modes.json_interval < 100) // 0.1s Modes.json_interval = 100; } else if (!strcmp(argv[j], "--json-location-accuracy") && more) { Modes.json_location_accuracy = atoi(argv[++j]); #endif } else { fprintf(stderr, "Unknown or not enough arguments for option '%s'.\n\n", argv[j]); showHelp(); exit(1); } } #ifndef _WIN32 // Setup for SIGWINCH for handling lines if (Modes.interactive) {signal(SIGWINCH, sigWinchCallback);} #endif if (Modes.mode_ac && Modes.oversample) { fprintf(stderr, "Warning: --modeac is currently ignored when --oversample is used;\n" " no ModeA/C messages will be decoded.\n"); } // Initialization log_with_timestamp("%s %s starting up.", MODES_DUMP1090_VARIANT, MODES_DUMP1090_VERSION); modesInit(); if (Modes.net_only) { fprintf(stderr,"Net-only mode, no RTL device or file open.\n"); } else if (Modes.filename == NULL) { if (modesInitRTLSDR() < 0) { exit(1); } } else { if (Modes.filename[0] == '-' && Modes.filename[1] == '\0') { Modes.fd = STDIN_FILENO; } else if ((Modes.fd = open(Modes.filename, #ifdef _WIN32 (O_RDONLY | O_BINARY) #else (O_RDONLY) #endif )) == -1) { perror("Opening data file"); exit(1); } } if (Modes.net) modesInitNet(); // init stats: Modes.stats_current.start = Modes.stats_current.end = Modes.stats_alltime.start = Modes.stats_alltime.end = Modes.stats_periodic.start = Modes.stats_periodic.end = Modes.stats_5min.start = Modes.stats_5min.end = Modes.stats_15min.start = Modes.stats_15min.end = mstime(); for (j = 0; j < 15; ++j) Modes.stats_1min[j].start = Modes.stats_1min[j].end = Modes.stats_current.start; // write initial json files so they're not missing writeJsonToFile("receiver.json", generateReceiverJson); writeJsonToFile("stats.json", generateStatsJson); writeJsonToFile("aircraft.json", generateAircraftJson); // If the user specifies --net-only, just run in order to serve network // clients without reading data from the RTL device if (Modes.net_only) { while (!Modes.exit) { struct timespec start_time; start_cpu_timing(&start_time); backgroundTasks(); end_cpu_timing(&start_time, &Modes.stats_current.background_cpu); usleep(100000); } } else { // Create the thread that will read the data from the device. pthread_mutex_lock(&Modes.data_mutex); pthread_create(&Modes.reader_thread, NULL, readerThreadEntryPoint, NULL); while (Modes.exit == 0) { struct timespec start_time; if (Modes.first_free_buffer == Modes.first_filled_buffer) { /* wait for more data. * we should be getting data every 50-60ms. wait for max 100ms before we give up and do some background work. * this is fairly aggressive as all our network I/O runs out of the background work! */ struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_nsec += 100000000; normalize_timespec(&ts); pthread_cond_timedwait(&Modes.data_cond, &Modes.data_mutex, &ts); // This unlocks Modes.data_mutex, and waits for Modes.data_cond } // Modes.data_mutex is locked, and possibly we have data. // copy out reader CPU time and reset it add_timespecs(&Modes.reader_cpu_accumulator, &Modes.stats_current.reader_cpu, &Modes.stats_current.reader_cpu); Modes.reader_cpu_accumulator.tv_sec = 0; Modes.reader_cpu_accumulator.tv_nsec = 0; if (Modes.first_free_buffer != Modes.first_filled_buffer) { // FIFO is not empty, process one buffer. struct mag_buf *buf; start_cpu_timing(&start_time); buf = &Modes.mag_buffers[Modes.first_filled_buffer]; // Process data after releasing the lock, so that the capturing // thread can read data while we perform computationally expensive // stuff at the same time. pthread_mutex_unlock(&Modes.data_mutex); if (Modes.oversample) { demodulate2400(buf); } else { demodulate2000(buf); } Modes.stats_current.samples_processed += buf->length; Modes.stats_current.samples_dropped += buf->dropped; end_cpu_timing(&start_time, &Modes.stats_current.demod_cpu); // Mark the buffer we just processed as completed. pthread_mutex_lock(&Modes.data_mutex); Modes.first_filled_buffer = (Modes.first_filled_buffer + 1) % MODES_MAG_BUFFERS; pthread_cond_signal(&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); } else { // Nothing to process this time around. pthread_mutex_unlock(&Modes.data_mutex); } start_cpu_timing(&start_time); backgroundTasks(); end_cpu_timing(&start_time, &Modes.stats_current.background_cpu); pthread_mutex_lock(&Modes.data_mutex); } pthread_mutex_unlock(&Modes.data_mutex); pthread_join(Modes.reader_thread,NULL); // Wait on reader thread exit pthread_cond_destroy(&Modes.data_cond); // Thread cleanup - only after the reader thread is dead! pthread_mutex_destroy(&Modes.data_mutex); } // If --stats were given, print statistics if (Modes.stats) { display_total_stats(); } cleanup_converter(Modes.converter_state); log_with_timestamp("Normal exit."); pthread_exit(0); #ifdef _WIN32 return (0); #endif }
// timeout in milliseconds OMX_ERRORTYPE COMXCoreComponent::WaitForEvent(OMX_EVENTTYPE eventType, long timeout) { #ifdef OMX_DEBUG_EVENTS CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForEvent %s wait event 0x%08x\n", m_componentName.c_str(), (int)eventType); #endif pthread_mutex_lock(&m_omx_event_mutex); struct timespec endtime; clock_gettime(CLOCK_REALTIME, &endtime); add_timespecs(endtime, timeout); while(true) { for (std::vector<omx_event>::iterator it = m_omx_events.begin(); it != m_omx_events.end(); it++) { omx_event event = *it; #ifdef OMX_DEBUG_EVENTS CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForEvent %s inlist event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 %d\n", m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2); #endif if(event.eEvent == OMX_EventError && event.nData1 == (OMX_U32)OMX_ErrorSameState && event.nData2 == 1) { #ifdef OMX_DEBUG_EVENTS CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForEvent %s remove event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 %d\n", m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2); #endif m_omx_events.erase(it); pthread_mutex_unlock(&m_omx_event_mutex); return OMX_ErrorNone; } else if(event.eEvent == OMX_EventError) { m_omx_events.erase(it); pthread_mutex_unlock(&m_omx_event_mutex); return (OMX_ERRORTYPE)event.nData1; } else if(event.eEvent == eventType) { #ifdef OMX_DEBUG_EVENTS CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForEvent %s remove event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 %d\n", m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2); #endif m_omx_events.erase(it); pthread_mutex_unlock(&m_omx_event_mutex); return OMX_ErrorNone; } } int retcode = pthread_cond_timedwait(&m_omx_event_cond, &m_omx_event_mutex, &endtime); if (retcode != 0) { if (timeout > 0) CLog::Log(LOGERROR, "COMXCoreComponent::WaitForEvent %s wait event 0x%08x timeout %ld\n", m_componentName.c_str(), (int)eventType, timeout); pthread_mutex_unlock(&m_omx_event_mutex); return OMX_ErrorMax; } } pthread_mutex_unlock(&m_omx_event_mutex); return OMX_ErrorNone; }
// timeout in milliseconds OMX_ERRORTYPE Component::waitForCommand(OMX_COMMANDTYPE command, OMX_U32 nData2, long timeout) //timeout default = 2000 { #ifdef DEBUG_COMMANDS ofLogVerbose(__func__) << "\n" << componentName << " command " << GetOMXCommandString(command) << "\n"; #endif pthread_mutex_lock(&event_mutex); struct timespec endtime; clock_gettime(CLOCK_REALTIME, &endtime); add_timespecs(endtime, timeout); OMX_EVENTTYPE eEvent = OMX_EventError; while(true) { for (std::vector<OMXEvent>::iterator it = omxEvents.begin(); it != omxEvents.end(); it++) { OMXEvent event = *it; eEvent = event.eEvent; //Ignore same state if(event.eEvent == OMX_EventError && event.nData1 == (OMX_U32)OMX_ErrorSameState && event.nData2 == 1) { omxEvents.erase(it); pthread_mutex_unlock(&event_mutex); return OMX_ErrorNone; } else { //Throw error if(event.eEvent == OMX_EventError) { ofLogVerbose(__func__) << "\n" << componentName << " command " << GetOMXCommandString(command) << "\n"; OMX_TRACE((OMX_ERRORTYPE)event.nData1); omxEvents.erase(it); pthread_mutex_unlock(&event_mutex); return (OMX_ERRORTYPE)event.nData1; } else { //Not an error amd the data we want if(event.eEvent == OMX_EventCmdComplete && event.nData1 == command && event.nData2 == nData2) { omxEvents.erase(it); pthread_mutex_unlock(&event_mutex); return OMX_ErrorNone; } } } } int retcode = pthread_cond_timedwait(&m_omx_event_cond, &event_mutex, &endtime); if (retcode != 0) { stringstream ss; ss << componentName << " TIMEOUT" << endl; ss << GetEventString(eEvent) << endl; ss << GetOMXCommandString(command) << endl; ss << nData2 << endl; ofLogError(__func__) << ss.str(); pthread_mutex_unlock(&event_mutex); return OMX_ErrorMax; } } pthread_mutex_unlock(&event_mutex); return OMX_ErrorNone; }
// timeout in milliseconds OMX_ERRORTYPE Component::waitForEvent(OMX_EVENTTYPE eventType, long timeout) { #ifdef DEBUG_EVENTS ofLogVerbose(__func__) << "\n" << componentName << "\n" << "eventType: " << GetEventString(eventType) << "\n"; #endif pthread_mutex_lock(&event_mutex); struct timespec endtime; clock_gettime(CLOCK_REALTIME, &endtime); add_timespecs(endtime, timeout); while(true) { for (vector<OMXEvent>::iterator it = omxEvents.begin(); it != omxEvents.end(); it++) { OMXEvent event = *it; //Same state - disregard if(event.eEvent == OMX_EventError && event.nData1 == (OMX_U32)OMX_ErrorSameState && event.nData2 == 1) { omxEvents.erase(it); pthread_mutex_unlock(&event_mutex); return OMX_ErrorNone; } else { if(event.eEvent == OMX_EventError) { omxEvents.erase(it); pthread_mutex_unlock(&event_mutex); return (OMX_ERRORTYPE)event.nData1; } else { //have the event we are looking for if(event.eEvent == eventType) { #ifdef DEBUG_EVENTS stringstream finishedInfo; finishedInfo << componentName << "\n"; finishedInfo << "RECEIVED EVENT, REMOVING" << "\n"; finishedInfo << "event.eEvent: " << GetEventString(event.eEvent) << "\n"; finishedInfo << "event.nData1: " << event.nData1 << "\n"; finishedInfo << "event.nData2: " << event.nData2 << "\n"; ofLogVerbose(__func__) << finishedInfo.str(); #endif omxEvents.erase(it); pthread_mutex_unlock(&event_mutex); return OMX_ErrorNone; } } } } int retcode = pthread_cond_timedwait(&m_omx_event_cond, &event_mutex, &endtime); if (retcode != 0) { ofLogError(__func__) << componentName << " waitForEvent Event: " << GetEventString(eventType) << " TIMED OUT at: " << timeout; pthread_mutex_unlock(&event_mutex); return OMX_ErrorMax; } } pthread_mutex_unlock(&event_mutex); return OMX_ErrorNone; }