[PATCH 2/2] staging/easycap: Upsample microphone audio

Mike Thomas rmthomas at sciolus.org
Sun Jul 11 09:54:51 UTC 2010


Upsampling from 8000 Hz mono to 32000 Hz stereo improves audio/video
synchronization when userspace programs adopt default buffering.  This
is an experimental feature.

Signed-off-by: Mike Thomas <rmthomas at sciolus.org>
---
 drivers/staging/easycap/easycap.h       |    2 +-
 drivers/staging/easycap/easycap_ioctl.c |   35 ++++++++++++++
 drivers/staging/easycap/easycap_low.c   |   66 ++++++++++----------------
 drivers/staging/easycap/easycap_main.c  |   15 ++++++-
 drivers/staging/easycap/easycap_sound.c |   78 ++++++++++++++++++++++++++++--
 5 files changed, 147 insertions(+), 49 deletions(-)

diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h
index ce8b16f..ad836d2 100644
--- a/drivers/staging/easycap/easycap.h
+++ b/drivers/staging/easycap/easycap.h
@@ -135,7 +135,7 @@
 #define USB_EASYCAP_VENDOR_ID	0x05e1
 #define USB_EASYCAP_PRODUCT_ID	0x0408
 
-#define EASYCAP_DRIVER_VERSION "0.8.2"
+#define EASYCAP_DRIVER_VERSION "0.8.21"
 #define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
 
 #define USB_SKEL_MINOR_BASE     192
diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c
index 5853bba..7227d73 100644
--- a/drivers/staging/easycap/easycap_ioctl.c
+++ b/drivers/staging/easycap/easycap_ioctl.c
@@ -1985,10 +1985,17 @@ case SNDCTL_DSP_GETCAPS: {
 	int caps;
 	JOT(8, "SNDCTL_DSP_GETCAPS\n");
 
+#if defined(UPSAMPLE)
+	if (true == peasycap->microphone)
+		caps = 0x04400000;
+	else
+		caps = 0x04400000;
+#else
 	if (true == peasycap->microphone)
 		caps = 0x02400000;
 	else
 		caps = 0x04400000;
+#endif /*UPSAMPLE*/
 
 	if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int)))
 		return -EFAULT;
@@ -1998,10 +2005,17 @@ case SNDCTL_DSP_GETFMTS: {
 	int incoming;
 	JOT(8, "SNDCTL_DSP_GETFMTS\n");
 
+#if defined(UPSAMPLE)
+	if (true == peasycap->microphone)
+		incoming = AFMT_S16_LE;
+	else
+		incoming = AFMT_S16_LE;
+#else
 	if (true == peasycap->microphone)
 		incoming = AFMT_S16_LE;
 	else
 		incoming = AFMT_S16_LE;
+#endif /*UPSAMPLE*/
 
 	if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
 		return -EFAULT;
@@ -2014,10 +2028,17 @@ case SNDCTL_DSP_SETFMT: {
 		return -EFAULT;
 	JOT(8, "........... %i=incoming\n", incoming);
 
+#if defined(UPSAMPLE)
 	if (true == peasycap->microphone)
 		outgoing = AFMT_S16_LE;
 	else
 		outgoing = AFMT_S16_LE;
+#else
+	if (true == peasycap->microphone)
+		outgoing = AFMT_S16_LE;
+	else
+		outgoing = AFMT_S16_LE;
+#endif /*UPSAMPLE*/
 
 	if (incoming != outgoing) {
 		JOT(8, "........... %i=outgoing\n", outgoing);
@@ -2037,10 +2058,17 @@ case SNDCTL_DSP_STEREO: {
 		return -EFAULT;
 	JOT(8, "........... %i=incoming\n", incoming);
 
+#if defined(UPSAMPLE)
+	if (true == peasycap->microphone)
+		incoming = 1;
+	else
+		incoming = 1;
+#else
 	if (true == peasycap->microphone)
 		incoming = 0;
 	else
 		incoming = 1;
+#endif /*UPSAMPLE*/
 
 	if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
 		return -EFAULT;
@@ -2053,10 +2081,17 @@ case SNDCTL_DSP_SPEED: {
 		return -EFAULT;
 	JOT(8, "........... %i=incoming\n", incoming);
 
+#if defined(UPSAMPLE)
+	if (true == peasycap->microphone)
+		incoming = 32000;
+	else
+		incoming = 48000;
+#else
 	if (true == peasycap->microphone)
 		incoming = 8000;
 	else
 		incoming = 48000;
+#endif /*UPSAMPLE*/
 
 	if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
 		return -EFAULT;
diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c
index e7c189a..ad1fc4c 100644
--- a/drivers/staging/easycap/easycap_low.c
+++ b/drivers/staging/easycap/easycap_low.c
@@ -827,7 +827,7 @@ static __u16 index = 0x0301;
 
 static unsigned char buffer[1];
 static __u16 length = 1;
-int rc;
+int rc, id1, id2;
 
 if (NULL == peasycap)
 	return -EFAULT;
@@ -883,46 +883,30 @@ SET(pusb_device, 0x0500, 0x008C);
 SET(pusb_device, 0x0506, 0x0001);
 SET(pusb_device, 0x0507, 0x0000);
 
-if (false == peasycap->microphone) {
-	/*-------------------------------------------------------------------*/
-	/*
-	*   SELECT AUDIO SOURCE "LINE IN" AND SET DEFAULT GAIN TO 0dB.
-	*/
-	/*-------------------------------------------------------------------*/
-	write_vt(pusb_device, 0x0002, 0x8000);
-	write_vt(pusb_device, 0x001C, 0x8000);
-
-	write_vt(pusb_device, 0x000E, 0x0000);
-	write_vt(pusb_device, 0x0010, 0x0000);
-	write_vt(pusb_device, 0x0012, 0x8000);
-	write_vt(pusb_device, 0x0016, 0x0000);
-
-	write_vt(pusb_device, 0x001A, 0x0404);
-	write_vt(pusb_device, 0x0002, 0x0000);
-	write_vt(pusb_device, 0x001C, 0x0000);
-} else {
-	/*-------------------------------------------------------------------*/
-	/*
-	*   SELECT AUDIO SOURCE "MIC" AND SET DEFAULT GAIN TO 0 dB.
-	*
-	*   REGISTER 0x000E CAN BE SET TO PROVIDE UP TO 34.5 dB ATTENTUATION,
-	*   BUT THIS HAS NOT PROVED NECESSARY FOR THE FEW SIGNAL SOURCES
-	*   TESTED HITHERTO.
-	*/
-	/*-------------------------------------------------------------------*/
-	write_vt(pusb_device, 0x0006, 0x8000);
-	write_vt(pusb_device, 0x001C, 0x8000);
-
-	write_vt(pusb_device, 0x000E, 0x0008);
-
-	write_vt(pusb_device, 0x0010, 0x0000);
-	write_vt(pusb_device, 0x0012, 0x8000);
-	write_vt(pusb_device, 0x0016, 0x0000);
-
-	write_vt(pusb_device, 0x001A, 0x0000);
-	write_vt(pusb_device, 0x0006, 0x0000);
-	write_vt(pusb_device, 0x001C, 0x0000);
-}
+id1 = read_vt(pusb_device, 0x007C);
+id2 = read_vt(pusb_device, 0x007E);
+SAY("0x%04X:0x%04X is audio vendor id\n", id1, id2);
+
+/*---------------------------------------------------------------------------*/
+/*
+*   SELECT AUDIO SOURCE "LINE IN" AND SET DEFAULT GAIN TO 0 dB.
+*
+*   THESE COMMANDS SEEM TO BE ACCEPTED (THOUGH POSSIBLY IGNORED) EVEN WHEN
+*   THERE IS NO SEPARATE AUDIO CHIP PRESENT.
+*/
+/*---------------------------------------------------------------------------*/
+
+write_vt(pusb_device, 0x0002, 0x8000);
+write_vt(pusb_device, 0x001C, 0x8000);
+
+write_vt(pusb_device, 0x000E, 0x0000);
+write_vt(pusb_device, 0x0010, 0x0000);
+write_vt(pusb_device, 0x0012, 0x8000);
+write_vt(pusb_device, 0x0016, 0x0000);
+
+write_vt(pusb_device, 0x001A, 0x0404);
+write_vt(pusb_device, 0x0002, 0x0000);
+write_vt(pusb_device, 0x001C, 0x0000);
 
 check_vt(pusb_device);
 
diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c
index b817c97..f7a65af 100644
--- a/drivers/staging/easycap/easycap_main.c
+++ b/drivers/staging/easycap/easycap_main.c
@@ -2490,6 +2490,10 @@ if (peasycap->video_idle) {
 				SAY("EMSGSIZE\n");
 				break;
 			}
+			case -ENOSPC: {
+				SAY("ENOSPC\n");
+				break;
+			}
 			default: {
 				SAY("0x%08X\n", rc);
 				break;
@@ -2571,6 +2575,9 @@ if (purb->status) {
 	case -ECONNRESET: {
 		SAY("-ECONNRESET\n"); break;
 	}
+	case -ENOSPC: {
+		SAY("ENOSPC\n"); break;
+	}
 	default: {
 		SAY("unknown error code 0x%08X\n", purb->status); break;
 	}
@@ -2630,6 +2637,9 @@ if (purb->status) {
 			case -ECONNRESET: {
 				strcpy(&errbuf[0], "-ECONNRESET"); break;
 			}
+			case -ENOSPC: {
+				SAY("ENOSPC\n"); break;
+			}
 			case -ESHUTDOWN: {
 				strcpy(&errbuf[0], "-ESHUTDOWN"); break;
 			}
@@ -2949,6 +2959,9 @@ if (peasycap->video_isoc_streaming) {
 		case -EMSGSIZE: {
 			SAY("EMSGSIZE\n");  break;
 		}
+		case -ENOSPC: {
+			SAY("ENOSPC\n"); break;
+		}
 		default: {
 			SAY("0x%08X\n", rc); break;
 		}
@@ -3861,7 +3874,7 @@ case 2: {
 			peasycap->ilk |= 0x02;
 			SAY("hardware is FOUR-CVBS\n");
 			peasycap->microphone = true;
-			peasycap->audio_pages_per_fragment = 2;
+			peasycap->audio_pages_per_fragment = 4;
 		} else if (256 == peasycap->audio_isoc_maxframesize) {
 			peasycap->ilk &= ~0x02;
 			SAY("hardware is CVBS+S-VIDEO\n");
diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/easycap/easycap_sound.c
index 2bf32e1..37eaf42 100644
--- a/drivers/staging/easycap/easycap_sound.c
+++ b/drivers/staging/easycap/easycap_sound.c
@@ -50,6 +50,10 @@ char errbuf[16];
 __u8 *p1, *p2;
 __s16 s16;
 int i, j, more, much, leap, rc;
+#if defined(UPSAMPLE)
+int k;
+__s16 oldaudio, newaudio, delta;
+#endif /*UPSAMPLE*/
 
 JOT(16, "\n");
 
@@ -99,6 +103,9 @@ if (peasycap->audio_idle) {
 			case -EMSGSIZE: {
 				SAY("EMSGSIZE\n");  break;
 			}
+			case -ENOSPC: {
+				SAY("ENOSPC\n");  break;
+			}
 			default: {
 				SAY("0x%08X\n", rc); break;
 			}
@@ -172,6 +179,9 @@ if (purb->status) {
 	case -ECONNRESET: {
 		SAY("-ECONNRESET\n"); break;
 	}
+	case -ENOSPC: {
+		SAY("ENOSPC\n");  break;
+	}
 	default: {
 		SAY("unknown error code 0x%08X\n", purb->status); break;
 	}
@@ -226,6 +236,10 @@ if (purb->status) {
  *  PROCEED HERE WHEN NO ERROR
  */
 /*---------------------------------------------------------------------------*/
+#if defined(UPSAMPLE)
+oldaudio = peasycap->oldaudio;
+#endif /*UPSAMPLE*/
+
 for (i = 0;  i < purb->number_of_packets; i++) {
 	switch (purb->iso_frame_desc[i].status) {
 	case  0: {
@@ -276,6 +290,9 @@ for (i = 0;  i < purb->number_of_packets; i++) {
 	case -ECONNRESET: {
 		strcpy(&errbuf[0], "-ECONNRESET"); break;
 	}
+	case -ENOSPC: {
+		strcpy(&errbuf[0], "-ENOSPC"); break;
+	}
 	case -ESHUTDOWN: {
 		strcpy(&errbuf[0], "-ESHUTDOWN"); break;
 	}
@@ -318,7 +335,7 @@ for (i = 0;  i < purb->number_of_packets; i++) {
 /*---------------------------------------------------------------------------*/
 /*
  *  COPY more BYTES FROM ISOC BUFFER TO AUDIO BUFFER,
- *  CONVERTING 8-BIT SAMPLES TO 16-BIT SIGNED LITTLE-ENDED SAMPLES IF NECESSARY
+ *  CONVERTING 8-BIT MONO TO 16-BIT SIGNED LITTLE-ENDIAN SAMPLES IF NECESSARY
  */
 /*---------------------------------------------------------------------------*/
 			while (more) {
@@ -386,8 +403,6 @@ for (i = 0;  i < purb->number_of_packets; i++) {
 
 				much = PAGE_SIZE - (int)(paudio_buffer->pto -\
 							 paudio_buffer->pgo);
-				if (much % 2)
-					JOT(8, "MISTAKE?  much is odd\n");
 
 				if (false == peasycap->microphone) {
 					if (much > more)
@@ -397,17 +412,57 @@ for (i = 0;  i < purb->number_of_packets; i++) {
 					p1 += much;
 					more -= much;
 				} else {
+#if defined(UPSAMPLE)
+					if (much % 16)
+						JOT(8, "MISTAKE? much" \
+						" is not divisible by 16\n");
+					if (much > (16 * \
+							more))
+						much = 16 * \
+							more;
+					p2 = (__u8 *)paudio_buffer->pto;
+
+					for (j = 0;  j < (much/16);  j++) {
+						newaudio =  ((int) *p1) - 128;
+						newaudio = 128 * \
+								newaudio;
+
+						delta = (newaudio - oldaudio) \
+									/ 4;
+						s16 = oldaudio + delta;
+
+						for (k = 0;  k < 4;  k++) {
+							*p2 = (0x00FF & s16);
+							*(p2 + 1) = (0xFF00 & \
+								s16) >> 8;
+							p2 += 2;
+							*p2 = (0x00FF & s16);
+							*(p2 + 1) = (0xFF00 & \
+								s16) >> 8;
+							p2 += 2;
+
+							s16 += delta;
+						}
+						p1++;
+						more--;
+						oldaudio = s16;
+					}
+#else
 					if (much > (2 * more))
 						much = 2 * more;
 					p2 = (__u8 *)paudio_buffer->pto;
 
 					for (j = 0;  j < (much / 2);  j++) {
 						s16 =  ((int) *p1) - 128;
-						*p2      = (0xFF00 & s16) >> 8;
-						*(p2 + 1) = (0x00FF & s16);
+						s16 = 128 * \
+								s16;
+						*p2 = (0x00FF & s16);
+						*(p2 + 1) = (0xFF00 & s16) >> \
+									8;
 						p1++;  p2 += 2;
 						more--;
 					}
+#endif /*UPSAMPLE*/
 				}
 				(paudio_buffer->pto) += much;
 			}
@@ -417,6 +472,11 @@ for (i = 0;  i < purb->number_of_packets; i++) {
 			"%i=purb->iso_frame_desc[i].status\n", \
 				purb->iso_frame_desc[i].status);
 	}
+
+#if defined(UPSAMPLE)
+peasycap->oldaudio = oldaudio;
+#endif /*UPSAMPLE*/
+
 }
 /*---------------------------------------------------------------------------*/
 /*
@@ -453,6 +513,9 @@ if (peasycap->audio_isoc_streaming) {
 		case -EMSGSIZE: {
 			SAY("EMSGSIZE\n");  break;
 		}
+		case -ENOSPC: {
+			SAY("ENOSPC\n");  break;
+		}
 		default: {
 			SAY("0x%08X\n", rc); break;
 		}
@@ -764,7 +827,7 @@ if (peasycap->audio_sample) {
 	mean = peasycap->audio_niveau;
 	sdr = signed_div(mean, peasycap->audio_sample);
 
-	JOT(12, "%8lli=mean  %8lli=meansquare after %lli samples, =>\n", \
+	JOT(8, "%8lli=mean  %8lli=meansquare after %lli samples, =>\n", \
 				sdr.quotient, above, peasycap->audio_sample);
 
 	sdr = signed_div(above, 32768);
@@ -902,6 +965,9 @@ if (!peasycap->audio_isoc_streaming) {
 					case -EMSGSIZE: {
 						SAY("EMSGSIZE\n"); break;
 					}
+					case -ENOSPC: {
+						SAY("ENOSPC\n"); break;
+					}
 					default: {
 						SAY("unknown error code %i\n",\
 								 rc); break;
-- 
1.7.0.4






More information about the devel mailing list