Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Enable USB audio device detection

Monitor add/remove uevents for USB audio devices and trigger output device changes

Change-Id: I23b075006a37a92882a6f33d9ffc229e2eafcc6a
  • Loading branch information...
commit de382599962d429a0e5a9f38ebf49543d5e33ed8 1 parent 02ead04
authored December 04, 2012
151  services/java/com/android/server/WiredAccessoryObserver.java
@@ -34,9 +34,12 @@
34 34
 import java.io.File;
35 35
 import java.io.FileReader;
36 36
 import java.io.FileNotFoundException;
  37
+import java.io.BufferedReader;
37 38
 import java.util.ArrayList;
38 39
 import java.util.Arrays;
39 40
 import java.util.List;
  41
+import java.util.regex.Matcher;
  42
+import java.util.regex.Pattern;
40 43
 
41 44
 /**
42 45
  * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock.
@@ -197,6 +200,9 @@ public WiredAccessoryObserver(Context context) {
197 200
         }
198 201
         context.registerReceiver(new BootCompletedReceiver(),
199 202
             new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
  203
+        
  204
+        // Observe ALSA usb audio events
  205
+        this.mUsbAudioObserver.startObserving("MAJOR=116");
200 206
     }
201 207
 
202 208
     private final class SettingsChangedReceiver extends BroadcastReceiver {
@@ -388,4 +394,149 @@ public void handleMessage(Message msg) {
388 394
             mWakeLock.release();
389 395
         }
390 396
     };
  397
+    
  398
+	private final UEventObserver mUsbAudioObserver = new UEventObserver() {
  399
+		public void onUEvent(UEventObserver.UEvent event) {
  400
+			if(LOG) Slog.v(WiredAccessoryObserver.TAG, "USB AUDIO UEVENT: " + event.toString());
  401
+			String action = event.get("ACTION");
  402
+			String devpath = event.get("DEVPATH");
  403
+			String major = event.get("MAJOR");
  404
+			String minor = event.get("MINOR");
  405
+			String devname = event.get("DEVNAME");
  406
+			if(LOG) Slog.v(WiredAccessoryObserver.TAG, "onUEvent(device) :: action = " + action + ", MAJOR = " + major + ", MINOR = " + minor + ", DEVPATH = " + devpath);
  407
+			
  408
+			String cardNumber;
  409
+			String deviceNumber;
  410
+			String channels;
  411
+			
  412
+			if (major.equals("116")) {
  413
+				
  414
+				String devpath_lower = devpath.toLowerCase();
  415
+				
  416
+				if ((devpath_lower.contains("usb")) && (!devpath_lower.contains("gadget")) && (devname.endsWith("p"))) {
  417
+					cardNumber = Character.toString(devname.charAt(8));
  418
+					deviceNumber = Character.toString(devname.charAt(10));
  419
+					channels = String.valueOf(WiredAccessoryObserver.this.getChannels(cardNumber));
  420
+					if(LOG) Slog.v(WiredAccessoryObserver.TAG, "cardNumber="+ cardNumber + " deviceNumber=" + deviceNumber + " channels=" + channels);
  421
+					
  422
+					int state = 0;
  423
+					
  424
+					if (action.equals("add")) {
  425
+						state = 1;
  426
+					} else {
  427
+						state = 0;
  428
+					}
  429
+					
  430
+					// Update USB audio details (and then inform the system that an USB audio device has been connected)
  431
+					WiredAccessoryObserver.this.update_usbaudio(state, channels, cardNumber, deviceNumber);	
  432
+				}
  433
+			}
  434
+		}
  435
+	};
  436
+	
  437
+	private int getChannels(String cardNumber) {
  438
+		int channels = 0;
  439
+		String streamContent = "";
  440
+		String streamPath = "/proc/asound/card" + cardNumber + "/stream0";
  441
+		
  442
+		// Parse channel count from /proc/asound/card[n]/stream0
  443
+		try {
  444
+			FileReader file = new FileReader(streamPath);
  445
+			BufferedReader br = new BufferedReader(new FileReader(streamPath));
  446
+			
  447
+			String line;
  448
+			while ((line = br.readLine()) != null) {
  449
+				streamContent += line;
  450
+			}
  451
+			
  452
+			br.close();
  453
+			
  454
+			Pattern regex = Pattern.compile("Playback:.*?Channels: .*?(\\d)", Pattern.DOTALL);
  455
+			Matcher regexMatcher = regex.matcher(streamContent);
  456
+			if (regexMatcher.find()) {
  457
+				channels = Integer.parseInt(regexMatcher.group(1));
  458
+			}
  459
+			
  460
+			if(LOG) Slog.v(TAG, "parsed channels = " + channels);
  461
+		}
  462
+		catch(FileNotFoundException e) {
  463
+			Slog.e(TAG, "Unable to get channels for " + streamPath);
  464
+		}
  465
+		catch(NumberFormatException e) {
  466
+			Slog.e(TAG, "Unable to parse channels for " + streamPath);
  467
+		}
  468
+		catch(Exception e){
  469
+			Slog.e(TAG, "" , e);
  470
+		}
  471
+		
  472
+		if(channels > 0) {
  473
+			return channels;
  474
+		}
  475
+		
  476
+		return 2;
  477
+	}
  478
+	
  479
+	private final void update_usbaudio(int state, String channels, String cardNumber, String deviceNumber) {
  480
+		try {
  481
+			// Send AUDIO_BECOMING_NOISY intent to warn applications of output switch
  482
+			Intent localIntent = new Intent("android.media.AUDIO_BECOMING_NOISY");
  483
+			this.mContext.sendBroadcast(localIntent);
  484
+			
  485
+			UsbAudioData localUsbAudioData = new UsbAudioData();
  486
+			localUsbAudioData.setUsbAudioData(state, channels,cardNumber, deviceNumber);
  487
+			
  488
+			this.mWakeLock.acquire();
  489
+			
  490
+			this.mHandler_usbAudio.sendMessageDelayed(this.mHandler_usbAudio.obtainMessage(0, localUsbAudioData), 500);
  491
+			
  492
+		} finally {
  493
+		}
  494
+	}
  495
+	
  496
+	private final Handler mHandler_usbAudio = new Handler() {
  497
+		public void handleMessage(Message message) {
  498
+			
  499
+			UsbAudioData usbAudioData = (UsbAudioData)message.obj;
  500
+			
  501
+			// Send USB_AUDIO_ACCESSORY_PLUG intent to notify that an USB audio device has been connected.
  502
+			Intent localIntent = new Intent("android.intent.action.USB_AUDIO_ACCESSORY_PLUG");
  503
+			localIntent.putExtra("state", usbAudioData.getState());
  504
+			localIntent.putExtra("card", Integer.parseInt(usbAudioData.getCardNumber()));
  505
+			localIntent.putExtra("device", Integer.parseInt(usbAudioData.getDeviceNumber()));
  506
+			localIntent.putExtra("channels", Integer.parseInt(usbAudioData.getChannels()));
  507
+			WiredAccessoryObserver.this.mContext.sendStickyBroadcast(localIntent);
  508
+			
  509
+			WiredAccessoryObserver.this.mWakeLock.release();
  510
+		}
  511
+	};
  512
+	
  513
+	private final class UsbAudioData {
  514
+		private String cardNumber;
  515
+		private String channels;
  516
+		private String deviceNumber;
  517
+		private int state;
  518
+
  519
+		public String getCardNumber() {
  520
+			return this.cardNumber;
  521
+		}
  522
+
  523
+		public String getChannels() {
  524
+			return this.channels;
  525
+		}
  526
+
  527
+		public String getDeviceNumber() {
  528
+			return this.deviceNumber;
  529
+		}
  530
+
  531
+		public int getState() {
  532
+			return this.state;
  533
+		}
  534
+
  535
+		public void setUsbAudioData(int state, String channels, String cardNumber, String deviceNumber) {
  536
+			this.state = state;
  537
+			this.channels = channels;
  538
+			this.cardNumber = cardNumber;
  539
+			this.deviceNumber = deviceNumber;
  540
+		}
  541
+	}
391 542
 }

0 notes on commit de38259

Please sign in to comment.
Something went wrong with that request. Please try again.