jack2 icon indicating copy to clipboard operation
jack2 copied to clipboard

JACK port for the QNX operating system

Open twischer-adit opened this issue 6 years ago • 6 comments

JACK can be build for QNX and is working fine. I tested with different playback use cases so far.

I provided a makefile calling the WAF build tooling.

I used the following commands for testing

jackd -R -P 80 -d alsa -P pcmC0D0p -p 768 -n 3 -S
jack_simple_client

twischer-adit avatar May 22 '19 09:05 twischer-adit

The latest update introduces the following diff:

diff --git a/linux/alsa/JackAlsaDriver.cpp b/linux/alsa/JackAlsaDriver.cpp
index a8962e1..6fcdf48 100644
--- a/linux/alsa/JackAlsaDriver.cpp
+++ b/linux/alsa/JackAlsaDriver.cpp
@@ -205,7 +205,6 @@ int JackAlsaDriver::Detach()
 }
 
 #ifndef __QNXNTO__
-/* del6kor : ToDo : why is strndup not avaiable despite the indludes*/
 extern "C" char* get_control_device_name(const char * device_name)
 {
     char * ctl_name;
@@ -238,7 +237,6 @@ extern "C" char* get_control_device_name(const char * device_name)
 #endif
 
 #ifndef __QNXNTO__
-/* del6kor : ToDo : is this needed ? */
 static int card_to_num(const char* device)
 {
     int err;
@@ -969,8 +967,13 @@ void SetTime(jack_time_t time)
 int Restart()
 {
     int res;
-    if ((res = g_alsa_driver->Stop()) == 0) {
-        res = g_alsa_driver->Start();
+    if ((res = g_alsa_driver->Stop()) != 0) {
+        jack_error("restart: stop driver failed");
+        return res;
+    }
+    if ((res = g_alsa_driver->Start()) != 0) {
+        jack_error("restart: start driver failed");
+        return res;
     }
     return res;
 }
diff --git a/linux/alsa/alsa_driver.c b/linux/alsa/alsa_driver.c
index 72f97a6..1e7eeb4 100644
--- a/linux/alsa/alsa_driver.c
+++ b/linux/alsa/alsa_driver.c
@@ -411,7 +411,6 @@ alsa_driver_allocate_buffer(alsa_driver_t *driver, int frames, int channels, boo
 	}
 
 	jack_error ("ALSA: could not allocate audio buffer");
-	alsa_driver_delete(driver);
 	return -1;
 }
 
@@ -1401,6 +1400,7 @@ alsa_driver_start (alsa_driver_t *driver)
 
 		if (alsa_driver_get_channel_addresses (driver,
 					0, &pavail, 0, &poffset)) {
+			jack_error("silence failed, get channel addresses");
 			return -1;
 		}
 
@@ -1481,7 +1481,8 @@ alsa_driver_stop (alsa_driver_t *driver)
 
 	if (driver->playback_handle) {
 #ifdef __QNXNTO__
-		err = snd_pcm_plugin_flush(driver->playback_handle, SND_PCM_CHANNEL_PLAYBACK);
+		/* In case of playback: Drain discards the frames */
+		err = snd_pcm_plugin_playback_drain(driver->playback_handle);
 #else
 		err = snd_pcm_drop (driver->playback_handle);
 #endif
@@ -1496,6 +1497,7 @@ alsa_driver_stop (alsa_driver_t *driver)
 	    || driver->capture_and_playback_not_synced) {
 		if (driver->capture_handle) {
 #ifdef __QNXNTO__
+			/* In case of capture: Flush discards the frames */
 			err = snd_pcm_plugin_flush(driver->capture_handle, SND_PCM_CHANNEL_CAPTURE);
 #else
 			err = snd_pcm_drop (driver->capture_handle);
@@ -1556,7 +1558,6 @@ alsa_driver_get_status (alsa_driver_t *driver)
 	}
 
 #ifdef __QNXNTO__
-	/* ToDo : ldevi : Can be moved a different func? s*/
 	memset (&status, 0, sizeof (status));
 	status.channel = driver->capture_handle ? SND_PCM_CHANNEL_CAPTURE :
 	                                          SND_PCM_CHANNEL_PLAYBACK;
@@ -1598,7 +1599,7 @@ alsa_driver_xrun_recovery (alsa_driver_t *driver, float *delayed_usecs)
 	    && driver->process_count > XRUN_REPORT_DELAY) {
 		driver->xrun_count++;
 #ifdef __QNXNTO__
-		/* ldevi : ToDo Check if there is a replacement*/
+		/* Timestamp api's are not available as per QNX Documentation */
 		*delayed_usecs = 0;
 #else
 		struct timeval now, diff, tstamp;
@@ -1625,6 +1626,7 @@ alsa_driver_xrun_recovery (alsa_driver_t *driver, float *delayed_usecs)
 	}
 
 	if (alsa_driver_restart (driver)) {
+		jack_error("xrun recovery failed to restart driver");
 		return -1;
 	}
 	return 0;
@@ -1663,22 +1665,7 @@ alsa_driver_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int s
 static snd_pcm_sframes_t
 alsa_driver_avail(alsa_driver_t *driver, snd_pcm_t *pcm, bool is_capture)
 {
-	int err;
-	snd_pcm_channel_status_t status = {0, };
-
-    status.channel = is_capture;
-    err = snd_pcm_plugin_status (pcm, &status);
-	if (err < 0)
-		return err;
-
-	switch (status.status) {
-	case SND_PCM_STATUS_UNDERRUN:
-	case SND_PCM_STATUS_OVERRUN:
-	case SND_PCM_STATUS_UNSECURE:
-	case SND_PCM_STATUS_CHANGE:
-		return -EPIPE;
-	}
-
+	/* QNX guarantees that after poll() event at least one perido is available */
 	return driver->frames_per_cycle;
 }
 #else
@@ -2485,23 +2472,27 @@ alsa_driver_open (alsa_driver_t *driver, bool is_capture)
 
 		case EINVAL:
 			jack_error ("the state of handle or the mode is invalid "
-				"or invalid state change occured \"%s\" for playback",
-				is_capture ? driver->alsa_name_capture : driver->alsa_name_playback);
+				"or invalid state change occured \"%s\" for %s",
+				is_capture ? driver->alsa_name_capture : driver->alsa_name_playback,
+				is_capture ? "capture" : "playback");
 			break;
 
 		case ENOENT:
-			jack_error ("device \"%s\"  does not exist for playback",
-				is_capture ? driver->alsa_name_capture : driver->alsa_name_playback);
+			jack_error ("device \"%s\"  does not exist for %s",
+				is_capture ? driver->alsa_name_capture : driver->alsa_name_playback,
+				is_capture ? "capture" : "playback");
 			break;
 
 		case ENOMEM:
-			jack_error ("Not enough memory available for allocation for \"%s\" for playback",
-				is_capture ? driver->alsa_name_capture : driver->alsa_name_playback);
+			jack_error ("Not enough memory available for allocation for \"%s\" for %s",
+				is_capture ? driver->alsa_name_capture : driver->alsa_name_playback,
+				is_capture ? "capture" : "playback");
 			break;
 
 		case SND_ERROR_INCOMPATIBLE_VERSION:
-			jack_error ("Version mismatch \"%s\" for playback",
-				is_capture ? driver->alsa_name_capture : driver->alsa_name_playback);
+			jack_error ("Version mismatch \"%s\" for %s",
+				is_capture ? driver->alsa_name_capture : driver->alsa_name_playback,
+				is_capture ? "capture" : "playback");
 			break;
 		}
 		alsa_driver_delete (driver);

It mainly removes TODO comments and solves some minor QNX specific issues.

twischer-adit avatar Jun 05 '20 12:06 twischer-adit

Merging this is tricky, because I have no device with such architecture. Is there any way we can add a CI check for QNX? (the osx CI build is broken at the moment, I know, will fix sometime soon. just takes ages to verify any possible fix)

falkTX avatar Jun 10 '20 20:06 falkTX

Hello @falkTX,

I have not yet touched CI. Are you aware of any good introduction? What would we need to provide to get it build for QNX? I expect the build is running on Linux with some cross compile environment, right?

twischer-adit avatar Jun 11 '20 06:06 twischer-adit

Mostly all it needs is a script or set of instructions to automatically build what is needed, even better if it can be tested afterwards. If you can tell me how you cross-compile, I might be able to add it in.

falkTX avatar Jun 11 '20 09:06 falkTX

Hi @falkTX, I have done a short research. The instructions to install the QNX compiler and the headers can be found in [1].

But I am not sure if QNX would provide a license for free for this purpose. You can get a 30-day evaluation license for free [2]. Licenses for education are also provided for free [3]. There it is mentioned that such licenses are for research purpose. Therefore may be QNX would offer such a license for this project. Would you like to raise this question to QNX as the maintainer of this project?

[1] http://www.qnx.com/developers/docs/6.5.0/index.jsp?topic=%2Fcom.qnx.doc.momentics_installation_guide%2Flinux_hosts.html&anchor=Install [2] http://www.qnx.com/products/evaluation/ [3] http://www.qnx.com/company/education/

twischer-adit avatar Jun 17 '20 14:06 twischer-adit

oh, so QNX is not an open system? nevermind then, I have no interest on such things.

you can leave the PR open so others can check the status and know that this exists. but I won't be the one merging it.

falkTX avatar Jun 17 '20 15:06 falkTX