Index: pjproject/branches/projects/android/pjmedia/src/pjmedia-audiodev/opensl_dev.c
===================================================================
--- pjproject/branches/projects/android/pjmedia/src/pjmedia-audiodev/opensl_dev.c	(revision 4211)
+++ pjproject/branches/projects/android/pjmedia/src/pjmedia-audiodev/opensl_dev.c	(revision 4215)
@@ -35,4 +35,6 @@
 #include <SLES/OpenSLES.h>
 #include <SLES/OpenSLES_Android.h>
+#include <sys/system_properties.h>
+#include <android/api-level.h>
 
 #define THIS_FILE	"opensl_dev.c"
@@ -70,4 +72,7 @@
     pjmedia_aud_play_cb play_cb;
 
+    pj_timestamp	play_timestamp;
+    pj_timestamp	rec_timestamp;
+    
     pj_bool_t		rec_thread_initialized;
     pj_thread_desc	rec_thread_desc;
@@ -81,4 +86,5 @@
     SLObjectItf         playerObj;
     SLPlayItf           playerPlay;
+    SLVolumeItf         playerVol;
     unsigned            playerBufferSize;
     char               *playerBuffer[NUM_BUFFERS];
@@ -174,4 +180,5 @@
         frame.buf = buf = stream->playerBuffer[stream->playerBufIdx++];
         frame.size = stream->playerBufferSize;
+        frame.timestamp.u64 = stream->play_timestamp.u64;
         frame.bit_info = 0;
         
@@ -179,4 +186,7 @@
         if (status != PJ_SUCCESS || frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
             pj_bzero(buf, stream->playerBufferSize);
+        
+        stream->play_timestamp.u64 += stream->param.samples_per_frame /
+                                      stream->param.channel_count;
         
         result = (*bq)->Enqueue(bq, buf, stream->playerBufferSize);
@@ -216,8 +226,11 @@
         frame.buf = buf = stream->recordBuffer[stream->recordBufIdx++];
         frame.size = stream->recordBufferSize;
-        frame.timestamp.u64 = 0;
+        frame.timestamp.u64 = stream->rec_timestamp.u64;
         frame.bit_info = 0;
         
         status = (*stream->rec_cb)(stream->user_data, &frame);
+        
+        stream->rec_timestamp.u64 += stream->param.samples_per_frame /
+                                     stream->param.channel_count;
         
         /* And now enqueue next buffer */
@@ -379,7 +392,6 @@
     
     pj_ansi_strcpy(info->name, "OpenSL ES Audio");
-    info->default_samples_per_sec = 16000;
-    info->caps = PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING |
-                 PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
+    info->default_samples_per_sec = 8000;
+    info->caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
     info->input_count = 1;
     info->output_count = 1;
@@ -422,5 +434,4 @@
     param->samples_per_frame = adi.default_samples_per_sec * 20 / 1000;
     param->bits_per_sample = 16;
-    param->flags = adi.caps;
     param->input_latency_ms = PJMEDIA_SND_DEFAULT_REC_LATENCY;
     param->output_latency_ms = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
@@ -486,8 +497,11 @@
         SLDataSink audioSnk = {&loc_outmix, NULL};
         /* Audio interface */
-        const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE,
-                                      SL_IID_VOLUME/*,
-                                      SL_IID_ANDROIDCONFIGURATION*/};
-        const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
+        const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE,
+                                      SL_IID_VOLUME,
+                                      SL_IID_ANDROIDCONFIGURATION};
+        const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
+                                  SL_BOOLEAN_FALSE};
+        SLAndroidConfigurationItf playerConfig;
+        SLint32 streamType = SL_ANDROID_STREAM_VOICE;
         
         /* Create audio player */
@@ -495,5 +509,5 @@
                                                         &stream->playerObj,
                                                         &audioSrc, &audioSnk,
-                                                        2, ids, req);
+                                                        3, ids, req);
         if (result != SL_RESULT_SUCCESS) {
             PJ_LOG(3, (THIS_FILE, "Cannot create audio player: %d", result));
@@ -501,18 +515,17 @@
         }
 
-        /*
-        SLAndroidConfigurationItf playerConfig;
-        SLint32 streamType = SL_ANDROID_STREAM_VOICE;
+        /* Set Android configuration */
         result = (*stream->playerObj)->GetInterface(stream->playerObj,
                                                     SL_IID_ANDROIDCONFIGURATION,
                                                     &playerConfig);
-        if (result != SL_RESULT_SUCCESS) {
-            PJ_LOG(4, (THIS_FILE, "Cannot get android configuration iface"));
-        }
-        result = (*playerConfig)->SetConfiguration(playerConfig,
-                                                   SL_ANDROID_KEY_STREAM_TYPE,
-                                                   &streamType,
-                                                   sizeof(SLint32));
-        */
+        if (result == SL_RESULT_SUCCESS && playerConfig) {
+            result = (*playerConfig)->SetConfiguration(
+                         playerConfig, SL_ANDROID_KEY_STREAM_TYPE,
+                         &streamType, sizeof(SLint32));
+        }
+        if (result != SL_RESULT_SUCCESS) {
+            PJ_LOG(4, (THIS_FILE, "Warning: Unable to set android "
+                                  "player configuration"));
+        }
         
         /* Realize the player */
@@ -541,4 +554,9 @@
             goto on_error;
         }
+        
+        /* Get the volume interface */
+        result = (*stream->playerObj)->GetInterface(stream->playerObj,
+                                                    SL_IID_VOLUME,
+                                                    &stream->playerVol);
         
         /* Register callback on the buffer queue */
@@ -569,6 +587,8 @@
         SLDataSink audioSnk = {&loc_bq, &format_pcm};
         /* Audio interface */
-        const SLInterfaceID ids[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
-        const SLboolean req[1] = {SL_BOOLEAN_TRUE};
+        const SLInterfaceID ids[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
+                                      SL_IID_ANDROIDCONFIGURATION};
+        const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE};
+        SLAndroidConfigurationItf recorderConfig;
         
         /* Create audio recorder
@@ -578,5 +598,5 @@
                                                           &stream->recordObj,
                                                           &audioSrc, &audioSnk,
-                                                          1, ids, req);
+                                                          2, ids, req);
         if (result != SL_RESULT_SUCCESS) {
             PJ_LOG(3, (THIS_FILE, "Cannot create recorder: %d", result));
@@ -584,6 +604,5 @@
         }
 
-        /*
-        SLAndroidConfigurationItf recorderConfig;
+        /* Set Android configuration */
         result = (*stream->recordObj)->GetInterface(stream->recordObj,
                                                     SL_IID_ANDROIDCONFIGURATION,
@@ -591,4 +610,5 @@
         if (result == SL_RESULT_SUCCESS) {
             SLint32 streamType = SL_ANDROID_RECORDING_PRESET_GENERIC;
+#if __ANDROID_API__ >= 14
             char sdk_version[PROP_VALUE_MAX];
             pj_str_t pj_sdk_version;
@@ -598,16 +618,17 @@
             pj_sdk_version = pj_str(sdk_version);
             sdk_v = pj_strtoul(&pj_sdk_version);
-            if (sdk_v >= 10)
-                streamType = 0x7;
-        
-            PJ_LOG(4, (THIS_FILE, "We have a stream type %d SDK : %d",
+            if (sdk_v >= 14)
+                streamType = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
+            PJ_LOG(4, (THIS_FILE, "Recording stream type %d, SDK : %d",
                                   streamType, sdk_v));
+#endif
             result = (*recorderConfig)->SetConfiguration(
                          recorderConfig, SL_ANDROID_KEY_RECORDING_PRESET,
                          &streamType, sizeof(SLint32));
-        } else {
-            PJ_LOG(4, (THIS_FILE, "Cannot get recorder config interface"));
-        }
-         */
+        }
+        if (result != SL_RESULT_SUCCESS) {
+            PJ_LOG(4, (THIS_FILE, "Warning: Unable to set android "
+                                  "recorder configuration"));
+        }
         
         /* Realize the recorder */
@@ -655,4 +676,9 @@
     }
     
+    if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
+	strm_set_cap(&stream->base, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
+                     &param->output_vol);
+    }
+    
     /* Done */
     stream->base.op = &opensl_strm_op;
@@ -672,4 +698,10 @@
     PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
     pj_memcpy(pi, &strm->param, sizeof(*pi));
+
+    if (strm_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
+                     &pi->output_vol) == PJ_SUCCESS)
+    {
+        pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
+    }    
     
     return PJ_SUCCESS;
@@ -686,15 +718,23 @@
     PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
     
-    PJ_UNUSED_ARG(strm);
-    
-    switch (cap) {
-        case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
-            status = PJ_SUCCESS;
-            break;
-        case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
-            status = PJ_SUCCESS;
-            break;
-        default:
-            break;
+    if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING &&
+	(strm->param.dir & PJMEDIA_DIR_PLAYBACK))
+    {
+        if (strm->playerVol) {
+            SLresult res;
+            SLmillibel vol, mvol;
+            
+            res = (*strm->playerVol)->GetMaxVolumeLevel(strm->playerVol,
+                                                        &mvol);
+            if (res == SL_RESULT_SUCCESS) {
+                res = (*strm->playerVol)->GetVolumeLevel(strm->playerVol,
+                                                         &vol);
+                if (res == SL_RESULT_SUCCESS) {
+                    *(int *)pval = ((int)vol - SL_MILLIBEL_MIN) * 100 /
+                                   ((int)mvol - SL_MILLIBEL_MIN);
+                    return PJ_SUCCESS;
+                }
+            }
+        }
     }
     
@@ -703,11 +743,31 @@
 
 /* API: set capability */
-static pj_status_t strm_set_cap(pjmedia_aud_stream *strm,
+static pj_status_t strm_set_cap(pjmedia_aud_stream *s,
                                 pjmedia_aud_dev_cap cap,
                                 const void *value)
 {
-    PJ_UNUSED_ARG(strm);
-    PJ_UNUSED_ARG(cap);
-    PJ_UNUSED_ARG(value);
+    struct opensl_aud_stream *strm = (struct opensl_aud_stream*)s;
+    
+    PJ_ASSERT_RETURN(s && value, PJ_EINVAL);
+
+    if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING &&
+	(strm->param.dir & PJMEDIA_DIR_PLAYBACK))
+    {
+        if (strm->playerVol) {
+            SLresult res;
+            SLmillibel vol, mvol;
+            
+            res = (*strm->playerVol)->GetMaxVolumeLevel(strm->playerVol,
+                                                        &mvol);
+            if (res == SL_RESULT_SUCCESS) {
+                vol = (SLmillibel)(*(int *)value *
+                      ((int)mvol - SL_MILLIBEL_MIN) / 100 + SL_MILLIBEL_MIN);
+                res = (*strm->playerVol)->SetVolumeLevel(strm->playerVol,
+                                                         vol);
+                if (res == SL_RESULT_SUCCESS)
+                    return PJ_SUCCESS;
+            }
+        }
+    }
 
     return PJMEDIA_EAUD_INVCAP;
@@ -795,7 +855,7 @@
     if (stream->playerBufQ && stream->playerPlay) {
         /* Wait until the PCM data is done playing, the buffer queue callback
-         will continue to queue buffers until the entire PCM data has been
-         played. This is indicated by waiting for the count member of the
-         SLBufferQueueState to go to zero.
+         * will continue to queue buffers until the entire PCM data has been
+         * played. This is indicated by waiting for the count member of the
+         * SLBufferQueueState to go to zero.
          */
 /*      
@@ -829,7 +889,9 @@
         /* Destroy the player */
         (*stream->playerObj)->Destroy(stream->playerObj);
+        /* Invalidate all associated interfaces */
         stream->playerObj = NULL;
         stream->playerPlay = NULL;
         stream->playerBufQ = NULL;
+        stream->playerVol = NULL;
     }
     
@@ -837,4 +899,5 @@
         /* Destroy the recorder */
         (*stream->recordObj)->Destroy(stream->recordObj);
+        /* Invalidate all associated interfaces */
         stream->recordObj = NULL;
         stream->recordRecord = NULL;
