* Prefer to send ISAC on clank.
* Add url option asc and arc to allow setting preferred audio send/receive codec.

TESTED=mobile as caller and callee:
pc-n7: pc sends opus, n7 sends isac 
pc-n4: pc sends opus, n4 sends isac
pc-pc opus-opus

R=braveyao@webrtc.org, juberti@google.com

Review URL: https://webrtc-codereview.appspot.com/2196006

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4742 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/samples/js/apprtc/apprtc.py b/samples/js/apprtc/apprtc.py
index 9df12a0..6bb65c8 100644
--- a/samples/js/apprtc/apprtc.py
+++ b/samples/js/apprtc/apprtc.py
@@ -45,6 +45,17 @@
     default_stun_server = 'stun.services.mozilla.com'
   return default_stun_server
 
+def get_preferred_audio_receive_codec():
+  return 'opus/48000'
+
+def get_preferred_audio_send_codec(user_agent):
+  # Empty string means no preference.
+  preferred_audio_send_codec = ''
+  # Prefer to send ISAC on Chrome for Android.
+  if 'Android' in user_agent and 'Chrome' in user_agent:
+    preferred_audio_send_codec = 'ISAC/16000'
+  return preferred_audio_send_codec
+
 def make_pc_config(stun_server, turn_server, ts_pwd):
   servers = []
   if turn_server:
@@ -300,6 +311,12 @@
     turn_server = self.request.get('ts')
     min_re = self.request.get('minre')
     max_re = self.request.get('maxre')
+    audio_send_codec = self.request.get('asc')
+    if not audio_send_codec:
+      audio_send_codec = get_preferred_audio_send_codec(user_agent)
+    audio_receive_codec = self.request.get('arc')
+    if not audio_receive_codec:
+      audio_receive_codec = get_preferred_audio_receive_codec()
     hd_video = self.request.get('hd')
     turn_url = 'https://computeengineondemand.appspot.com/'
     if hd_video.lower() == 'true':
@@ -382,7 +399,9 @@
                        'offer_constraints': json.dumps(offer_constraints),
                        'media_constraints': json.dumps(media_constraints),
                        'turn_url': turn_url,
-                       'stereo': stereo
+                       'stereo': stereo,
+                       'audio_send_codec': audio_send_codec,
+                       'audio_receive_codec': audio_receive_codec
                       }
     if unittest:
       target_page = 'test/test_' + unittest + '.html'
diff --git a/samples/js/apprtc/index.html b/samples/js/apprtc/index.html
index efbdfe8..71d3cd7 100644
--- a/samples/js/apprtc/index.html
+++ b/samples/js/apprtc/index.html
@@ -27,7 +27,8 @@
   var mediaConstraints = {{ media_constraints | safe }};
   var turnUrl = '{{ turn_url }}';
   var stereo = {{ stereo }};
-
+  var audio_send_codec = '{{ audio_send_codec }}';
+  var audio_receive_codec = '{{ audio_receive_codec }}';
   setTimeout(initialize, 1);
 </script>
 <div id="container" ondblclick="enterFullScreen()">
diff --git a/samples/js/apprtc/js/main.js b/samples/js/apprtc/js/main.js
index 6a9396b..b704f8c 100644
--- a/samples/js/apprtc/js/main.js
+++ b/samples/js/apprtc/js/main.js
@@ -14,8 +14,8 @@
 var msgQueue = [];
 // Set up audio and video regardless of what devices are present.
 var sdpConstraints = {'mandatory': {
-                        'OfferToReceiveAudio': true,
-                        'OfferToReceiveVideo': true }};
+                      'OfferToReceiveAudio': true,
+                      'OfferToReceiveVideo': true }};
 var isVideoMuted = false;
 var isAudioMuted = false;
 // Types of gathered ICE Candidates.
@@ -199,13 +199,21 @@
 }
 
 function setLocalAndSendMessage(sessionDescription) {
-  // Set Opus as the preferred codec in SDP if Opus is present.
-  sessionDescription.sdp = preferOpus(sessionDescription.sdp);
+  sessionDescription.sdp = maybePreferAudioReceiveCodec(sessionDescription.sdp);
   pc.setLocalDescription(sessionDescription,
        onSetSessionDescriptionSuccess, onSetSessionDescriptionError);
   sendMessage(sessionDescription);
 }
 
+function setRemote(message) {
+  // Set Opus in Stereo, if stereo enabled.
+  if (stereo)
+    message.sdp = addStereo(message.sdp);
+  message.sdp = maybePreferAudioSendCodec(message.sdp);
+  pc.setRemoteDescription(new RTCSessionDescription(message),
+       onSetSessionDescriptionSuccess, onSetSessionDescriptionError);
+}
+
 function sendMessage(message) {
   var msgString = JSON.stringify(message);
   console.log('C->S: ' + msgString);
@@ -224,18 +232,10 @@
   }
 
   if (message.type === 'offer') {
-    // Set Opus in Stereo, if stereo enabled.
-    if (stereo)
-      message.sdp = addStereo(message.sdp);
-    pc.setRemoteDescription(new RTCSessionDescription(message),
-         onSetSessionDescriptionSuccess, onSetSessionDescriptionError);
+    setRemote(message);
     doAnswer();
   } else if (message.type === 'answer') {
-    // Set Opus in Stereo, if stereo enabled.
-    if (stereo)
-      message.sdp = addStereo(message.sdp);
-    pc.setRemoteDescription(new RTCSessionDescription(message),
-         onSetSessionDescriptionSuccess, onSetSessionDescriptionError);
+    setRemote(message);
   } else if (message.type === 'candidate') {
     var candidate = new RTCIceCandidate({sdpMLineIndex: message.label,
                                          candidate: message.candidate});
@@ -297,7 +297,7 @@
 }
 
 function onCreateSessionDescriptionError(error) {
-  console.log('Failed to create session description: ' + error.name);
+  console.log('Failed to create session description: ' + error.toString());
 }
 
 function onSetSessionDescriptionSuccess() {
@@ -305,7 +305,7 @@
 }
 
 function onSetSessionDescriptionError(error) {
-  console.log('Failed to set session description: ' + error.name);
+  console.log('Failed to set session description: ' + error.toString());
 }
 
 function iceCandidateType(candidateSDP) {
@@ -533,8 +533,34 @@
   }
 }
 
-// Set Opus as the default audio codec if it's present.
-function preferOpus(sdp) {
+function maybePreferAudioSendCodec(sdp) {
+  if (audio_send_codec == '') {
+    console.log('No preference on audio send codec.');
+    return sdp;
+  }
+  console.log('Prefer audio send codec: ' + audio_send_codec);
+  return preferAudioCodec(sdp, audio_send_codec);
+}
+
+function maybePreferAudioReceiveCodec(sdp) {
+  if (audio_receive_codec == '') {
+    console.log('No preference on audio receive codec.');
+    return sdp;
+  }
+  console.log('Prefer audio receive codec: ' + audio_receive_codec);
+  return preferAudioCodec(sdp, audio_receive_codec);
+}
+
+// Set |codec| as the default audio codec if it's present.
+// The format of |codec| is 'NAME/RATE', e.g. 'opus/48000'.
+function preferAudioCodec(sdp, codec) {
+  var fields = codec.split('/');
+  if (fields.length != 2) {
+    console.log('Invalid codec setting: ' + codec);
+    return sdp;
+  }
+  var name = fields[0];
+  var rate = fields[1];
   var sdpLines = sdp.split('\r\n');
 
   // Search for m line.
@@ -547,13 +573,14 @@
   if (mLineIndex === null)
     return sdp;
 
-  // If Opus is available, set it as the default in m line.
+  // If the codec is available, set it as the default in m line.
   for (var i = 0; i < sdpLines.length; i++) {
-    if (sdpLines[i].search('opus/48000') !== -1) {
-      var opusPayload = extractSdp(sdpLines[i], /:(\d+) opus\/48000/i);
-      if (opusPayload)
+    if (sdpLines[i].search(name + '/' + rate) !== -1) {
+      var regexp = new RegExp(':(\\d+) ' + name + '\\/' + rate, 'i');
+      var payload = extractSdp(sdpLines[i], regexp);
+      if (payload)
         sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex],
-                                               opusPayload);
+                                               payload);
       break;
     }
   }