Ejemplo n.º 1
0
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."));
	}
}
Ejemplo n.º 2
0
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."));
	}
}
Ejemplo n.º 3
0
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."));
	}
}