void ALSAInput::InputThread() { try { Logger::LogInfo("[ALSAInput::InputThread] " + QObject::tr("Input thread started.")); std::vector<uint8_t> buffer(m_alsa_period_size * m_channels * 2); bool has_first_samples = false; int64_t first_timestamp = 0; // value won't be used, but GCC gives a warning otherwise while(!m_should_stop) { // wait until samples are available // This is not actually required since snd_pcm_readi is blocking, but unlike snd_pcm_read, // this function has a timeout value. This means the input thread won't hang if the device turns out to be dead. int res = snd_pcm_wait(m_alsa_pcm, 1000); if(res == 0) { continue; } if(res < 0) { if(res == -EPIPE) { ALSARecoverAfterOverrun(m_alsa_pcm); PushAudioHole(); } else { Logger::LogError("[ALSAInput::InputThread] " + QObject::tr("Error: Can't check whether samples are available!")); throw ALSAException(); } continue; } // read the samples snd_pcm_sframes_t samples_read = snd_pcm_readi(m_alsa_pcm, buffer.data(), m_alsa_period_size); if(samples_read < 0) { if(samples_read == -EPIPE) { ALSARecoverAfterOverrun(m_alsa_pcm); PushAudioHole(); } else { Logger::LogError("[ALSAInput::InputThread] " + QObject::tr("Error: Can't read samples!")); throw ALSAException(); } continue; } if(samples_read <= 0) continue; int64_t timestamp = hrt_time_micro(); // skip the first samples if(has_first_samples) { if(timestamp > first_timestamp + START_DELAY) { // push the samples int64_t time = timestamp - (int64_t) samples_read * (int64_t) 1000000 / (int64_t) m_sample_rate; PushAudioSamples(m_sample_rate, m_channels, samples_read, buffer.data(), AV_SAMPLE_FMT_S16, time); } } else { has_first_samples = true; first_timestamp = timestamp; } } Logger::LogInfo("[ALSAInput::InputThread] " + QObject::tr("Input thread stopped.")); } catch(const std::exception& e) { m_error_occurred = true; Logger::LogError("[ALSAInput::InputThread] " + QObject::tr("Exception '%1' in input thread.").arg(e.what())); } catch(...) { m_error_occurred = true; Logger::LogError("[ALSAInput::InputThread] " + QObject::tr("Unknown exception in input thread.")); } }
void JACKInput::InputThread() { try { Logger::LogInfo("[JACKInput::InputThread] " + Logger::tr("Input thread started.")); while(!m_should_stop) { // process connect commands // JACK will send notifications when we connect/disconnect ports, so holding the lock while doing this is a bad idea. // It seems that JACK is designed in such a way that a single misbehaving application can lock up the entire server, so let's avoid that. std::vector<ConnectCommand> connect_commands; { SharedLock lock(&m_shared_data); connect_commands.swap(lock->m_connect_commands); } for(ConnectCommand &cmd : connect_commands) { if(cmd.m_connect) { Logger::LogInfo("[JACKInput::InputThread] " + Logger::tr("Connecting port %1 to %2.") .arg(QString::fromStdString(cmd.m_source)).arg(QString::fromStdString(cmd.m_destination))); jack_connect(m_jack_client, cmd.m_source.c_str(), cmd.m_destination.c_str()); } else { Logger::LogInfo("[JACKInput::InputThread] " + Logger::tr("Disconnecting port %1 from %2.") .arg(QString::fromStdString(cmd.m_source)).arg(QString::fromStdString(cmd.m_destination))); jack_disconnect(m_jack_client, cmd.m_source.c_str(), cmd.m_destination.c_str()); } } // is there a new message? unsigned int message_size; char *message = m_message_queue.PrepareReadMessage(&message_size); if(message == NULL) { usleep(20000); continue; } // read the message assert(message_size >= sizeof(enum_eventtype)); enum_eventtype type = *((enum_eventtype*) message); message += sizeof(enum_eventtype); if(type == EVENTTYPE_HOLE) { PushAudioHole(); } if(type == EVENTTYPE_DATA) { assert(message_size >= sizeof(enum_eventtype) + sizeof(Event_Data)); assert(message_size >= sizeof(enum_eventtype) + sizeof(Event_Data) + ((Event_Data*) message)->m_sample_count * m_channels * sizeof(float)); PushAudioSamples(m_channels, ((Event_Data*) message)->m_sample_rate, AV_SAMPLE_FMT_FLT, ((Event_Data*) message)->m_sample_count, (uint8_t*) (message + sizeof(Event_Data)), ((Event_Data*) message)->m_timestamp); } // go to next message m_message_queue.ReadMessage(); } Logger::LogInfo("[JACKInput::InputThread] " + Logger::tr("Input thread stopped.")); } catch(const std::exception& e) { m_error_occurred = true; Logger::LogError("[JACKInput::InputThread] " + Logger::tr("Exception '%1' in input thread.").arg(e.what())); } catch(...) { m_error_occurred = true; Logger::LogError("[JACKInput::InputThread] " + Logger::tr("Unknown exception in input thread.")); } }
void JACKInput::InputThread() { try { Logger::LogInfo("[JACKInput::InputThread] " + Logger::tr("Input thread started.")); while(!m_should_stop) { unsigned int message_size; char *message = m_message_queue.PrepareReadMessage(&message_size); if(message == NULL) { // process connect commands { SharedLock lock(&m_shared_data); for(ConnectCommand &cmd : lock->m_connect_commands) { if(cmd.m_connect) { Logger::LogInfo("[JACKInput::InputThread] " + Logger::tr("Connecting port %1 to %2.") .arg(QString::fromStdString(cmd.m_source)).arg(QString::fromStdString(cmd.m_destination))); jack_connect(m_jack_client, cmd.m_source.c_str(), cmd.m_destination.c_str()); } else { Logger::LogInfo("[JACKInput::InputThread] " + Logger::tr("Disconnecting port %1 from %2.") .arg(QString::fromStdString(cmd.m_source)).arg(QString::fromStdString(cmd.m_destination))); jack_disconnect(m_jack_client, cmd.m_source.c_str(), cmd.m_destination.c_str()); } } lock->m_connect_commands.clear(); } usleep(10000); continue; } // read the message assert(message_size >= sizeof(enum_eventtype)); enum_eventtype type = *((enum_eventtype*) message); message += sizeof(enum_eventtype); if(type == EVENTTYPE_HOLE) { PushAudioHole(); } if(type == EVENTTYPE_DATA) { assert(message_size >= sizeof(enum_eventtype) + sizeof(Event_Data)); assert(message_size >= sizeof(enum_eventtype) + sizeof(Event_Data) + ((Event_Data*) message)->m_sample_count * m_channels * sizeof(float)); PushAudioSamples(m_channels, ((Event_Data*) message)->m_sample_rate, AV_SAMPLE_FMT_FLT, ((Event_Data*) message)->m_sample_count, (uint8_t*) (message + sizeof(Event_Data)), ((Event_Data*) message)->m_timestamp); } // go to next message m_message_queue.ReadMessage(); } Logger::LogInfo("[JACKInput::InputThread] " + Logger::tr("Input thread stopped.")); } catch(const std::exception& e) { m_error_occurred = true; Logger::LogError("[JACKInput::InputThread] " + Logger::tr("Exception '%1' in input thread.").arg(e.what())); } catch(...) { m_error_occurred = true; Logger::LogError("[JACKInput::InputThread] " + Logger::tr("Unknown exception in input thread.")); } }