Home | History | Annotate | Download | only in src
      1 /*
      2  INTEL CONFIDENTIAL
      3  Copyright 2009 Intel Corporation All Rights Reserved.
      4  The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material contains trade secrets and proprietary and confidential information of Intel or its suppliers and licensors. The Material is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intels prior express written permission.
      5 
      6  No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing.
      7 */
      8 
      9 /**
     10  * SECTION:mixaudio
     11  * @short_description: Object to support a single stream playback using hardware accelerated decoder.
     12  * @include: mixaudio.h
     13  *
     14  * #MixAudio object provide thread-safe API for application and/or multimedia framework to take advantage of Intel Smart Sound Technology(TM) driver for hardware audio decode and render.
     15  *
     16  * Each #MixAudio object represents one streaming session with the Intel Smart Sound driver and provides configuration and control of the decoding and playback options.
     17  *
     18  * The #MixAudio object also support integration with Intel Audio Manager service.
     19  *
     20  * An application can utilize the #MixAudio object by calling the following sequence:
     21  * <orderedlist numeration="arabic">
     22  * <listitem>mix_audio_new() to create a #MixAudio instance.</listitem>
     23  * <listitem>mix_audio_initialize() to allocate Intel Smart Sound Technology resource.</listitem>
     24  * <listitem>mix_audio_configure() to configure stream parameters.</listitem>
     25  * <listitem>mix_audio_decode() can be called repeatedly for decoding and, optionally, rendering.</listitem>
     26  * <listitem>mix_audio_start() is called after the 1st mix_audio_decode() method to start rendering.</listitem>
     27  * <listitem>mix_audio_stop_drain() is called after the last buffer is passed for decoding in with mix_audio_decode(). </listitem>
     28  * <listitem>mix_audio_deinitialize() to free resource once playback is completed.</listitem>
     29  * </orderedlist>
     30  *
     31  * Since mix_audio_decode() is a blocking call during playback, the following methods are called in a seperate thread to control progress:
     32  * <itemizedlist>
     33  * <listitem>mix_audio_start()</listitem>
     34  * <listitem>mix_audio_pause()</listitem>
     35  * <listitem>mix_audio_resume()</listitem>
     36  * <listitem>mix_audio_stop_drop()</listitem>
     37  * </itemizedlist>
     38  */
     39 
     40 /**
     41  * SECTION:mixaudiotypes
     42  * @title: Mix Audio Types
     43  * @short_description: Miscellanous types used by #MixAudio API.
     44  * @include: mixaudiotypes.h
     45  *
     46  * Miscellanous types used by #MixAudio API.
     47 */
     48 
     49 #include <sys/types.h>
     50 #include <sys/stat.h>
     51 #include <fcntl.h>
     52 #include <sys/ioctl.h>
     53 #include <errno.h>
     54 #include <unistd.h>
     55 #include <sys/uio.h>
     56 #include <string.h>
     57 
     58 #include <glib.h>
     59 #include <glib/gprintf.h>
     60 #include <mixlog.h>
     61 #include "mixaudio.h"
     62 
     63 #ifdef AUDIO_MANAGER
     64 #include "amhelper.h"
     65 #endif
     66 
     67 #ifndef MIXAUDIO_CURRENT
     68 #define MIXAUDIO_CURRENT 0
     69 #endif
     70 #ifndef MIXAUDIO_AGE
     71 #define MIXAUDIO_AGE 0
     72 #endif
     73 
     74 /* Include this now but it will change when driver updates.
     75    We would want to build against a kernel dev package if that
     76    is available.
     77 */
     78 #include <linux/types.h>
     79 #include "intel_sst_ioctl.h"
     80 #include "sst_proxy.h"
     81 
     82 #ifdef G_LOG_DOMAIN
     83 #undef G_LOG_DOMAIN
     84 #define G_LOG_DOMAIN    ((gchar*)"mixaudio")
     85 #endif
     86 
     87 /**
     88  * LPE_DEVICE:
     89  *
     90  * LPE Device location.
     91  */
     92 static const char* LPE_DEVICE="/dev/lpe";
     93 /* #define LPE_DEVICE "/dev/lpe" */
     94 
     95 #define _LOCK(obj) g_static_rec_mutex_lock(obj);
     96 #define _UNLOCK(obj) g_static_rec_mutex_unlock(obj);
     97 
     98 #define _UNLOCK_RETURN(obj, res) { _UNLOCK(obj); return res; }
     99 
    100 typedef enum {
    101   MIX_STREAM_PAUSED_DRAINING = MIX_STREAM_LAST,
    102   MIX_STREAM_INTERNAL_LAST
    103 } MixStreamStateInternal;
    104 
    105 
    106 MIX_RESULT mix_audio_initialize_default(MixAudio *mix, MixCodecMode mode, MixAudioInitParams *aip, MixDrmParams *drminitparams);
    107 MIX_RESULT mix_audio_configure_default(MixAudio *mix, MixAudioConfigParams *audioconfigparams, MixDrmParams *drmparams);
    108 MIX_RESULT mix_audio_decode_default(MixAudio *mix, const MixIOVec *iovin, gint iovincnt, guint64 *insize, MixIOVec *iovout, gint iovoutcnt, guint64 *outsize);
    109 MIX_RESULT mix_audio_capture_encode_default(MixAudio *mix, MixIOVec *iovout, gint iovoutcnt);
    110 MIX_RESULT mix_audio_start_default(MixAudio *mix);
    111 MIX_RESULT mix_audio_stop_drop_default(MixAudio *mix);
    112 MIX_RESULT mix_audio_stop_drain_default(MixAudio *mix);
    113 MIX_RESULT mix_audio_pause_default(MixAudio *mix);
    114 MIX_RESULT mix_audio_resume_default(MixAudio *mix);
    115 MIX_RESULT mix_audio_get_timestamp_default(MixAudio *mix, guint64 *msecs);
    116 MIX_RESULT mix_audio_set_mute_default(MixAudio *mix, gboolean mute);
    117 MIX_RESULT mix_audio_get_mute_default(MixAudio *mix, gboolean* muted);
    118 MIX_RESULT mix_audio_get_max_vol_default(MixAudio *mix, gint *maxvol);
    119 MIX_RESULT mix_audio_get_min_vol_default(MixAudio *mix, gint *minvol);
    120 MIX_RESULT mix_audio_get_volume_default(MixAudio *mix, gint *currvol, MixVolType type);
    121 MIX_RESULT mix_audio_set_volume_default(MixAudio *mix, gint currvol, MixVolType type, gulong msecs, MixVolRamp ramptype);
    122 MIX_RESULT mix_audio_deinitialize_default(MixAudio *mix);
    123 MIX_RESULT mix_audio_get_stream_state_default(MixAudio *mix, MixStreamState *streamState);
    124 MIX_RESULT mix_audio_get_state_default(MixAudio *mix, MixState *state);
    125 MIX_RESULT mix_audio_is_am_available_default(MixAudio *mix, MixAudioManager am, gboolean *avail);
    126 MIX_RESULT mix_audio_get_output_configuration_default(MixAudio *mix, MixAudioConfigParams **audioconfigparams);
    127 
    128 static gboolean g_IAM_available = FALSE;
    129 MIX_RESULT mix_audio_am_unregister(MixAudio *mix, MixAudioConfigParams *audioconfigparams);
    130 MIX_RESULT mix_audio_am_register(MixAudio *mix, MixAudioConfigParams *audioconfigparams);
    131 MIX_RESULT mix_audio_AM_Change(MixAudioConfigParams *oldparams, MixAudioConfigParams *newparams);
    132 
    133 static void mix_audio_finalize(GObject *obj);
    134 G_DEFINE_TYPE (MixAudio, mix_audio, G_TYPE_OBJECT);
    135 
    136 static gboolean has_FW_INFO = FALSE;
    137 static struct snd_sst_fw_info cur_FW_INFO = {{0}};
    138 
    139 static MIX_RESULT mix_audio_FW_INFO(MixAudio *mix);
    140 static MIX_RESULT mix_audio_SST_SET_PARAMS(MixAudio *mix, MixAudioConfigParams *params);
    141 static MIX_RESULT mix_audio_SST_writev(MixAudio *mix, const MixIOVec *iovin, gint iovincnt, guint64 *insize);
    142 static MIX_RESULT mix_audio_SST_STREAM_DECODE(MixAudio *mix, const MixIOVec *iovin, gint iovincnt, guint64 *insize, MixIOVec *iovout, gint iovoutcnt, guint64 *outsize);
    143 static void mix_audio_debug_dump(MixAudio *mix);
    144 
    145 static guint g_log_handler=0;
    146 static void mix_audio_log(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data);
    147 
    148 /**
    149  * mix_acp_print_params:
    150  * @obj: TBD
    151  *
    152  * This method is to print acp param. It is a hidden implementation within MixAudioConfigParams.
    153 */
    154 void mix_acp_print_params(MixAudioConfigParams *obj);
    155 
    156 static void mix_audio_init (MixAudio *self)
    157 {
    158   self->useIAM = FALSE;
    159   self->streamID = 0; // TODO: Find out the invalid value for stream ID when integrates with IAM.
    160   self->amStreamID = 0;         // TODO: as above
    161   self->streamState = MIX_STREAM_NULL;
    162   self->encoding = NULL;
    163   self->fileDescriptor = -1;
    164   self->state = MIX_STATE_UNINITIALIZED;
    165   self->codecMode = MIX_CODING_INVALID;
    166   self->am_registered = FALSE;
    167 
    168   /* private member initialization */
    169   g_static_rec_mutex_init (&self->streamlock);
    170   g_static_rec_mutex_init (&self->controllock);
    171 
    172   self->audioconfigparams = NULL;
    173   self->deviceState = MIX_AUDIO_DEV_CLOSED;
    174 
    175 #ifdef LPESTUB
    176   g_message("MixAudio running in stub mode!");
    177   self->ts_last = 0;
    178   self->ts_elapsed = 0;
    179 #endif
    180 
    181   self->bytes_written=0;
    182 
    183 }
    184 
    185 void _mix_aip_initialize (void);
    186 
    187 static void mix_audio_class_init (MixAudioClass *klass)
    188 {
    189   GObjectClass *gobject_class = (GObjectClass*)klass;
    190 
    191   gobject_class->finalize = mix_audio_finalize;
    192 
    193   // Init thread before any threads/sync object are used.
    194   if (!g_thread_supported ()) g_thread_init (NULL);
    195 
    196   /* Init some global vars */
    197   g_IAM_available = FALSE;
    198 
    199   // base implementations
    200   klass->initialize = mix_audio_initialize_default;
    201   klass->configure = mix_audio_configure_default;
    202   klass->decode = mix_audio_decode_default;
    203   klass->capture_encode = mix_audio_capture_encode_default;
    204   klass->start = mix_audio_start_default;
    205   klass->stop_drop = mix_audio_stop_drop_default;
    206   klass->stop_drain = mix_audio_stop_drain_default;
    207   klass->pause = mix_audio_pause_default;
    208   klass->resume = mix_audio_resume_default;
    209   klass->get_timestamp = mix_audio_get_timestamp_default;
    210   klass->set_mute = mix_audio_set_mute_default;
    211   klass->get_mute = mix_audio_get_mute_default;
    212   klass->get_max_vol = mix_audio_get_max_vol_default;
    213   klass->get_min_vol = mix_audio_get_min_vol_default;
    214   klass->get_volume = mix_audio_get_volume_default;
    215   klass->set_volume = mix_audio_set_volume_default;
    216   klass->deinitialize = mix_audio_deinitialize_default;
    217   klass->get_stream_state = mix_audio_get_stream_state_default;
    218   klass->get_state = mix_audio_get_state_default;
    219   klass->is_am_available = mix_audio_is_am_available_default;
    220   klass->get_output_configuration = mix_audio_get_output_configuration_default;
    221 
    222   // Set log handler...
    223   if (!g_log_handler)
    224   {
    225     // Get Environment variable
    226     // See mix_audio_log for details
    227     const gchar* loglevel = g_getenv("MIX_AUDIO_DEBUG");
    228     guint64 ll = 0;
    229     if (loglevel)
    230     {
    231       if (g_strstr_len(loglevel,-1, "0x") == loglevel)
    232       {
    233         // Hex string
    234         ll = g_ascii_strtoull(loglevel+2, NULL, 16);
    235       }
    236       else
    237       {
    238         // Decimal string
    239         ll = g_ascii_strtoull(loglevel, NULL, 10);
    240       }
    241     }
    242     guint32 mask = (guint32)ll;
    243     g_log_handler = g_log_set_handler(G_LOG_DOMAIN, 0xffffffff, mix_audio_log, (gpointer)mask);
    244 /*
    245     g_debug("DEBUG Enabled");
    246     g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%s", "LOG Enabled");
    247     g_message("MESSAGE Enabled");
    248     g_warning("WARNING Enabled");
    249     g_critical("CRITICAL Enabled");
    250     g_error("ERROR Enabled");
    251 */
    252   }
    253 }
    254 
    255 static void mix_audio_log(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
    256 {
    257   // Log message based on a mask.
    258   // Mask could be read from MIX_AUDIO_DEBUG environment variable
    259   // mask is a bit mask specifying the message to print. The lsb (0) is "ERROR" and graduating increasing
    260   // value as describe in GLogLevelFlags structure. Not that lsb in GLogLevelFlags is not "ERROR" and
    261   // here we shifted the log_level to ignore the first 2 values in GLogLevelFlags, making ERROR align to
    262   // the lsb.
    263   static const gchar* lognames[] = {"error", "critical", "warning", "message", "log", "debug"};
    264   guint32 mask = (guint32)user_data & ((G_LOG_LEVEL_MASK & log_level) >> 2);
    265   gint index = 0;
    266 
    267   GTimeVal t = {0};
    268 
    269   // convert bit mask back to index.
    270   index = ffs(mask) - 1;
    271 
    272   if ((index<0) || (index >= (sizeof(lognames)/sizeof(lognames[0])))) return;
    273 
    274   g_get_current_time(&t);
    275   g_printerr("%" G_GUINT64_FORMAT ":%s-%s: %s\n",
    276     ((guint64)1000000 * t.tv_sec + (guint64)t.tv_usec),
    277     log_domain?log_domain:G_LOG_DOMAIN,
    278     lognames[index],
    279     message?message:"NULL");
    280 }
    281 
    282 MixAudio *mix_audio_new(void)
    283 {
    284   MixAudio *ret = g_object_new(MIX_TYPE_AUDIO, NULL);
    285 
    286   return ret;
    287 }
    288 
    289 void mix_audio_finalize(GObject *obj)
    290 {
    291   /* clean up here. */
    292   MixAudio *mix = MIX_AUDIO(obj);
    293 
    294   if (G_UNLIKELY(!mix)) return;
    295 
    296   /*
    297     We are not going to check the thread lock anymore in this method.
    298     If a thread is accessing the object it better still have a ref on this
    299     object and in that case, this method won't be called.
    300 
    301     The application have to risk access violation if it calls the methods in
    302     a thread without actually holding a reference.
    303   */
    304 
    305   g_debug("_finalized(). bytes written=%" G_GUINT64_FORMAT, mix->bytes_written);
    306 
    307   g_static_rec_mutex_free (&mix->streamlock);
    308   g_static_rec_mutex_free (&mix->controllock);
    309 
    310   if (mix->audioconfigparams)
    311   {
    312     mix_acp_unref(mix->audioconfigparams);
    313     mix->audioconfigparams = NULL;
    314   }
    315 }
    316 
    317 MixAudio *mix_audio_ref(MixAudio *mix)
    318 {
    319   if (G_UNLIKELY(!mix)) return NULL;
    320 
    321   return (MixAudio*)g_object_ref(G_OBJECT(mix));
    322 }
    323 
    324 MIX_RESULT mix_audio_initialize_default(MixAudio *mix, MixCodecMode mode, MixAudioInitParams *aip, MixDrmParams *drminitparams)
    325 {
    326   MIX_RESULT ret = MIX_RESULT_FAIL;
    327 
    328   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    329 
    330   // TODO: parse and process MixAudioInitParams. It is ignored for now.
    331 
    332   // initialized must be called with both thread-lock held, so no other operation is allowed.
    333 
    334   // try lock stream thread. If failed, a pending _decode/_encode/_drain is ongoing.
    335   if (!g_static_rec_mutex_trylock(&mix->streamlock)) return MIX_RESULT_WRONG_STATE;
    336 
    337   // also lock the control thread lock.
    338   _LOCK(&mix->controllock);
    339 
    340   if (mix->state == MIX_STATE_UNINITIALIZED)
    341   {
    342     // Only allowed in uninitialized state.
    343     switch (mode)
    344     {
    345       case MIX_CODING_DECODE:
    346       case MIX_CODING_ENCODE:
    347         {
    348           // Open device. Same flags to open for decode and encode?
    349 #ifdef LPESTUB
    350           //g_debug("Reading env var LPESTUB_FILE for data output file.\n");
    351           //const char* filename = g_getenv("LPESTUB_FILE");
    352           gchar *filename = NULL;
    353           GError *err = NULL;
    354           const gchar* fn = NULL;
    355 	  fn = g_getenv("MIX_AUDIO_OUTPUT");
    356 	  if (fn)
    357 	    mix->fileDescriptor = open(fn, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
    358 
    359           if (mix->fileDescriptor == -1)
    360           {
    361 	    mix->fileDescriptor = g_file_open_tmp ("mixaudio.XXXXXX", &filename, &err);
    362 
    363             if (err)
    364             {
    365               g_warning("Oops, cannot open temp file: Error message: %s", err->message);
    366             }
    367             else
    368             {
    369               g_debug("Opening %s as output data file.\n", filename);
    370             }
    371           }
    372           else
    373           {
    374             g_debug("Opening %s as output data file.\n", fn);
    375           }
    376           if (filename) g_free(filename);
    377 #else
    378           g_debug("Opening %s\n", LPE_DEVICE);
    379           mix->fileDescriptor = open(LPE_DEVICE, O_RDWR);
    380 #endif
    381           if (mix->fileDescriptor != -1)
    382           {
    383             mix->codecMode = mode;
    384             mix->state = MIX_STATE_INITIALIZED;
    385             ret = MIX_RESULT_SUCCESS;
    386             g_debug("open() succeeded. fd=%d", mix->fileDescriptor);
    387           }
    388           else
    389           {
    390             ret = MIX_RESULT_LPE_NOTAVAIL;
    391           }
    392         }
    393         break;
    394       default:
    395         ret = MIX_RESULT_INVALID_PARAM;
    396       break;
    397     }
    398   }
    399   else
    400   {
    401     ret = MIX_RESULT_WRONG_STATE;
    402   }
    403 
    404   _UNLOCK(&mix->controllock);
    405   _UNLOCK(&mix->streamlock);
    406 
    407   return ret;
    408 }
    409 
    410 gboolean mix_audio_am_is_available(void)
    411 {
    412   // return FALSE for now until IAM is available for integration.
    413   // TODO: Check IAM
    414   return FALSE;
    415 }
    416 
    417 gboolean mix_audio_base_am_is_enabled(MixAudio *mix)
    418 {
    419   // TODO: Check IAM usage
    420   return FALSE;
    421 }
    422 
    423 /**
    424  * mix_audio_SST_SET_PARAMS:
    425  * @mix: #MixAudio object.
    426  * @params: Audio parameter used to configure SST.
    427  * @returns: #MIX_RESULT indicating configuration result.
    428  *
    429  * This method setup up a SST stream with the given parameters. Note that even though
    430  * this method could succeed and SST stream is setup properly, client may still not be able
    431  * to use the session if other condition are met, such as a successfully set-up IAM, if used.
    432  */
    433 MIX_RESULT mix_audio_SST_SET_PARAMS(MixAudio *mix, MixAudioConfigParams *params)
    434 {
    435   MIX_RESULT ret = MIX_RESULT_SUCCESS;
    436 
    437   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    438 
    439   if (mix->state == MIX_STATE_UNINITIALIZED) return MIX_RESULT_NOT_INIT;
    440 
    441   if (!MIX_IS_AUDIOCONFIGPARAMS(params)) return MIX_RESULT_INVALID_PARAM;
    442 
    443   mix_acp_print_params(params);
    444 
    445   struct snd_sst_params sst_params = {0};
    446 
    447   gboolean converted = mix_sst_params_convert(params, &sst_params);
    448 
    449   if (converted)
    450   {
    451     // Setup the driver structure
    452     // We are assuming the configstream will always be called after open so the codec mode
    453     // should already been setup.
    454     sst_params.stream_id = mix->streamID;
    455     // We are not checking the codecMODE here for out-of-range...assuming we check that
    456     // during init...
    457     if (mix->codecMode == MIX_CODING_ENCODE)
    458       sst_params.ops = STREAM_OPS_CAPTURE;
    459     else sst_params.ops = STREAM_OPS_PLAYBACK;
    460 
    461      // hard-coded to support music only.
    462     sst_params.stream_type = 0x0; // stream_type 0x00 is STREAM_TYPE_MUSIC per SST doc.
    463 
    464     // SET_PARAMS
    465     int retVal = 0;
    466 
    467 #ifdef LPESTUB
    468     // Not calling the ioctl
    469 #else
    470     g_debug("Calling SNDRV_SST_STREAM_SET_PARAMS. fd=%d", mix->fileDescriptor);
    471     retVal = ioctl(mix->fileDescriptor, SNDRV_SST_STREAM_SET_PARAMS, &sst_params);
    472     g_debug("_SET_PARAMS returned %d", retVal);
    473 #endif
    474 
    475     if (!retVal)
    476     {
    477       // IOCTL success.
    478       switch (sst_params.result)
    479       {
    480         // Please refers to SST API doc for return value definition.
    481         case 5:
    482           g_debug("SET_PARAMS succeeded with Stream Parameter Modified.");
    483         case 0:
    484           // driver says ok, too.
    485           ret = MIX_RESULT_SUCCESS;
    486           mix->deviceState = MIX_AUDIO_DEV_ALLOCATED;
    487           mix->streamState = MIX_STREAM_STOPPED;
    488           mix->streamID = sst_params.stream_id;
    489           // clear old params
    490           if (MIX_IS_AUDIOCONFIGPARAMS(mix->audioconfigparams))
    491           {
    492             mix_acp_unref(mix->audioconfigparams);
    493             mix->audioconfigparams=NULL;
    494           }
    495           // replace with new one.
    496           mix->audioconfigparams = MIX_AUDIOCONFIGPARAMS(mix_params_dup(MIX_PARAMS(params)));
    497           // Note: do not set mix->state here because this state may rely op other than SET_PARAMS
    498           g_debug("SET_PARAMS succeeded streamID=%d.", mix->streamID);
    499           break;
    500         case 1:
    501           ret = MIX_RESULT_STREAM_NOTAVAIL;
    502           g_debug("SET_PARAMS failed STREAM not available.");
    503           break;
    504         case 2:
    505           ret = MIX_RESULT_CODEC_NOTAVAIL;
    506           g_debug("SET_PARAMS failed CODEC not available.");
    507           break;
    508         case 3:
    509           ret = MIX_RESULT_CODEC_NOTSUPPORTED;
    510           g_debug("SET_PARAMS failed CODEC not supported.");
    511           break;
    512         case 4:
    513           ret = MIX_RESULT_INVALID_PARAM;
    514           g_debug("SET_PARAMS failed Invalid Stream Parameters.");
    515           break;
    516         case 6:
    517           g_debug("SET_PARAMS failed Invalid Stream ID.");
    518         default:
    519           ret = MIX_RESULT_FAIL;
    520           g_critical("SET_PARAMS failed unexpectedly. Result code: %u\n", sst_params.result);
    521           break;
    522       }
    523     }
    524     else
    525     {
    526       // log errors
    527       ret = MIX_RESULT_SYSTEM_ERRNO;
    528       g_debug("Failed to SET_PARAMS. errno:0x%08x. %s\n", errno, strerror(errno));
    529     }
    530   }
    531   else
    532   {
    533     ret = MIX_RESULT_INVALID_PARAM;
    534   }
    535 
    536   return ret;
    537 }
    538 
    539 MIX_RESULT mix_audio_get_state_default(MixAudio *mix, MixState *state)
    540 {
    541   MIX_RESULT ret = MIX_RESULT_SUCCESS;
    542   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    543 
    544   if (state)
    545     *state = mix->state;
    546   else
    547     ret = MIX_RESULT_NULL_PTR;
    548 
    549   return ret;
    550 }
    551 
    552 MIX_RESULT mix_audio_decode_default(MixAudio *mix, const MixIOVec *iovin, gint iovincnt, guint64 *insize, MixIOVec *iovout, gint iovoutcnt, guint64 *outsize)
    553 {
    554   MIX_RESULT ret = MIX_RESULT_FAIL;
    555 
    556   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    557 
    558   if (!g_static_rec_mutex_trylock(&mix->streamlock)) return MIX_RESULT_WRONG_STATE;
    559 
    560   if (mix->state != MIX_STATE_CONFIGURED) _UNLOCK_RETURN(&mix->streamlock, MIX_RESULT_WRONG_STATE);
    561 
    562   if (MIX_ACP_DECODEMODE(mix->audioconfigparams) == MIX_DECODE_DIRECTRENDER)
    563     ret = mix_audio_SST_writev(mix, iovin, iovincnt, insize);
    564   else
    565     ret = mix_audio_SST_STREAM_DECODE(mix, iovin, iovincnt, insize, iovout, iovoutcnt, outsize);
    566 
    567   _UNLOCK(&mix->streamlock);
    568 
    569   return ret;
    570 }
    571 
    572 MIX_RESULT mix_audio_deinitialize_default(MixAudio *mix)
    573 {
    574   MIX_RESULT ret = MIX_RESULT_SUCCESS;
    575   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    576 
    577   if (!g_static_rec_mutex_trylock(&mix->streamlock)) return MIX_RESULT_WRONG_STATE;
    578 
    579 #ifdef AUDIO_MANAGER
    580   if (mix->amStreamID && (lpe_stream_unregister(mix->amStreamID) < 0)) {
    581     g_debug("lpe_stream_unregister failed\n");
    582     //return MIX_RESULT_FAIL;   // TODO: not sure what to do here
    583   }
    584 #endif
    585 
    586   _LOCK(&mix->controllock);
    587 
    588   if (mix->state == MIX_STATE_UNINITIALIZED)
    589     ret = MIX_RESULT_SUCCESS;
    590   else if ((mix->streamState != MIX_STREAM_STOPPED) && (mix->streamState != MIX_STREAM_NULL))
    591     ret = MIX_RESULT_WRONG_STATE;
    592   else
    593   {
    594     if (mix->fileDescriptor != -1)
    595     {
    596       g_debug("Closing fd=%d\n", mix->fileDescriptor);
    597       close(mix->fileDescriptor);
    598       mix->fileDescriptor = -1;
    599       mix->deviceState = MIX_AUDIO_DEV_CLOSED;
    600     }
    601     mix->state = MIX_STATE_UNINITIALIZED;
    602   }
    603 
    604   mix->bytes_written = 0;
    605 
    606   _UNLOCK(&mix->controllock);
    607   _UNLOCK(&mix->streamlock);
    608 
    609   return ret;
    610 }
    611 
    612 
    613 MIX_RESULT mix_audio_stop_drop_default(MixAudio *mix)
    614 {
    615   MIX_RESULT ret = MIX_RESULT_FAIL;
    616 
    617   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    618 
    619   _LOCK(&mix->controllock);
    620 
    621   if (mix->state != MIX_STATE_CONFIGURED)
    622     _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_NOT_CONFIGURED);
    623 
    624   // Will call DROP even if we are already stopped. It is needed to unblock any pending write() call.
    625 //  if (mix->streamState == MIX_STREAM_DRAINING)
    626 //    ret = MIX_RESULT_WRONG_STATE;
    627 //  else
    628   {
    629     int retVal = 0;
    630 #ifdef LPESTUB
    631     // Not calling ioctl.
    632 #else
    633     g_debug("Calling SNDRV_SST_STREAM_DROP. fd=%d", mix->fileDescriptor);
    634     retVal = ioctl(mix->fileDescriptor, SNDRV_SST_STREAM_DROP);
    635     g_debug("_DROP returned %d", retVal);
    636 #endif
    637 
    638     if (!retVal)
    639       {
    640         mix->streamState = MIX_STREAM_STOPPED;
    641         ret = MIX_RESULT_SUCCESS;
    642       }
    643     else
    644       {
    645         ret = MIX_RESULT_SYSTEM_ERRNO;
    646         g_debug("Failed to stop stream. Error:0x%08x. Unknown stream state.", errno);
    647       }
    648   }
    649 
    650   _UNLOCK(&mix->controllock);
    651 
    652   return ret;
    653 }
    654 
    655 MIX_RESULT mix_audio_stop_drain_default(MixAudio *mix)
    656 {
    657   MIX_RESULT ret = MIX_RESULT_FAIL;
    658   int retVal = 0;
    659 
    660   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    661 
    662   // No need to lock to check vars that won't be changed in this function
    663 
    664   if (g_static_rec_mutex_trylock(&mix->streamlock))
    665   {
    666     gboolean doDrain = FALSE;
    667 
    668     if (mix->state != MIX_STATE_CONFIGURED)
    669       _UNLOCK_RETURN(&mix->streamlock, MIX_RESULT_NOT_CONFIGURED);
    670 
    671     _LOCK(&mix->controllock);
    672     {
    673       if (mix->streamState == MIX_STREAM_STOPPED)
    674         ret = MIX_RESULT_SUCCESS;
    675       else if ((mix->streamState == MIX_STREAM_DRAINING) || mix->streamState == MIX_STREAM_PAUSED_DRAINING)
    676         ret = MIX_RESULT_WRONG_STATE;
    677       else
    678       {
    679         doDrain = TRUE;
    680         g_debug("MIX stream is DRAINING");
    681         mix->streamState = MIX_STREAM_DRAINING;
    682       }
    683     }
    684     _UNLOCK(&mix->controllock);
    685 
    686 
    687     if (doDrain)
    688     {
    689       // Calling the blocking DRAIN without holding the controllock
    690       // TODO: remove this ifdef when API becomes available.
    691   #ifdef LPESTUB
    692 
    693   #else
    694       //g_debug("Calling SNDRV_SST_STREAM_DRAIN. fd=0x%08x", mix->fileDescriptor);
    695       //retVal = ioctl(mix->fileDescriptor, SNDRV_SST_STREAM_DRAIN);
    696 //      g_warning("Calling SNDRV_SST_STREAM_DROP instead of SNDRV_SST_STREAM_DRAIN here since DRAIN is not yet integrated. There may be data loss. fd=%d", mix->fileDescriptor);
    697       g_debug("Calling SNDRV_SST_STREAM_DRAIN fd=%d", mix->fileDescriptor);
    698       retVal = ioctl(mix->fileDescriptor, SNDRV_SST_STREAM_DRAIN);
    699       g_debug("_DRAIN returned %d", retVal);
    700   #endif
    701 
    702       if (retVal)
    703       {
    704         _LOCK(&mix->controllock);
    705         if (mix->streamState != MIX_STREAM_STOPPED)
    706         {
    707           // DRAIN could return failed if DROP is called during DRAIN.
    708           // Any state resulting as a failed DRAIN would be error, execpt STOPPED.
    709           ret = MIX_RESULT_SYSTEM_ERRNO;
    710           g_debug("Failed to drain stream. Error:0x%08x. Unknown stream state.", errno);
    711         }
    712         _UNLOCK(&mix->controllock);
    713       }
    714       else
    715       {
    716         _LOCK(&mix->controllock);
    717         if ((mix->streamState != MIX_STREAM_DRAINING) &&
    718           (mix->streamState != MIX_STREAM_STOPPED))
    719         {
    720           // State is changed while in DRAINING. This should not be allowed and is a bug.
    721           g_warning("MIX Internal state error! DRAIN state(%u) changed!",mix->streamState);
    722           ret = MIX_RESULT_FAIL;
    723         }
    724         else
    725         {
    726           mix->streamState = MIX_STREAM_STOPPED;
    727           ret = MIX_RESULT_SUCCESS;
    728         }
    729         _UNLOCK(&mix->controllock);
    730       }
    731     }
    732 
    733     _UNLOCK(&mix->streamlock);
    734   }
    735   else
    736   {
    737     // Cannot obtain stream lock meaning there's a pending _decode/_encode.
    738     // Will not proceed.
    739     ret = MIX_RESULT_WRONG_STATE;
    740   }
    741 
    742   return ret;
    743 }
    744 
    745 MIX_RESULT mix_audio_start_default(MixAudio *mix)
    746 {
    747   MIX_RESULT ret = MIX_RESULT_FAIL;
    748 
    749   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    750 
    751   _LOCK(&mix->controllock);
    752 
    753   if (mix->state != MIX_STATE_CONFIGURED)
    754     _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_NOT_CONFIGURED);
    755 
    756   if (MIX_ACP_DECODEMODE(mix->audioconfigparams) == MIX_DECODE_DECODERETURN)
    757     _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_WRONGMODE);
    758 
    759   // Note this impl return success even if stream is already started.
    760   switch (mix->streamState)
    761   {
    762     case MIX_STREAM_PLAYING:
    763     case MIX_STREAM_PAUSED:
    764     case MIX_STREAM_PAUSED_DRAINING:
    765       ret = MIX_RESULT_SUCCESS;
    766       break;
    767     case MIX_STREAM_STOPPED:
    768       {
    769         int retVal = 0;
    770 #ifdef LPESTUB
    771         // Not calling ioctl.
    772 #else
    773         g_debug("Calling SNDRV_SST_STREAM_START. fd=%d", mix->fileDescriptor);
    774         retVal = ioctl(mix->fileDescriptor, SNDRV_SST_STREAM_START);
    775         g_debug("_START returned %d", retVal);
    776 #endif
    777         if (retVal)
    778         {
    779           ret = MIX_RESULT_SYSTEM_ERRNO;
    780           g_debug("Fail to START. Error:0x%08x. Stream state unchanged.", errno);
    781           mix_audio_debug_dump(mix);
    782         }
    783         else
    784         {
    785           mix->streamState = MIX_STREAM_PLAYING;
    786           ret = MIX_RESULT_SUCCESS;
    787         }
    788       }
    789       break;
    790     case MIX_STREAM_DRAINING:
    791     default:
    792       ret = MIX_RESULT_WRONG_STATE;
    793       break;
    794   }
    795 
    796   _UNLOCK(&mix->controllock);
    797 
    798 #ifdef LPESTUB
    799   if (MIX_SUCCEEDED(ret))
    800   {
    801     if (mix->ts_last == 0)
    802     {
    803       GTimeVal tval = {0};
    804       g_get_current_time(&tval);
    805       mix->ts_last = 1000ll * tval.tv_sec + tval.tv_usec / 1000;
    806     }
    807   }
    808 #endif
    809   return ret;
    810 }
    811 
    812 MIX_RESULT mix_audio_get_version(guint* major, guint *minor)
    813 {
    814   // simulate the way libtool generate version so the number synchronize with the filename.
    815   if (major)
    816     *major = MIXAUDIO_CURRENT-MIXAUDIO_AGE;
    817 
    818   if (minor)
    819     *minor = MIXAUDIO_AGE;
    820 
    821   return MIX_RESULT_SUCCESS;
    822 }
    823 
    824 MIX_RESULT mix_audio_configure_default(MixAudio *mix, MixAudioConfigParams *audioconfigparams, MixDrmParams *drmparams)
    825 {
    826   MIX_RESULT ret = MIX_RESULT_SUCCESS;
    827 
    828   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    829 
    830   // param checks
    831   if (!MIX_IS_AUDIOCONFIGPARAMS(audioconfigparams)) return MIX_RESULT_NOT_ACP;
    832   if (MIX_ACP_DECODEMODE(audioconfigparams) >= MIX_DECODE_LAST) return MIX_RESULT_INVALID_DECODE_MODE;
    833   if (!mix_acp_is_streamname_valid(audioconfigparams)) return MIX_RESULT_INVALID_STREAM_NAME;
    834 
    835   // If we cannot lock stream thread, data is flowing and we can't configure.
    836   if (!g_static_rec_mutex_trylock(&mix->streamlock)) return MIX_RESULT_WRONG_STATE;
    837 
    838   _LOCK(&mix->controllock);
    839 
    840   // Check all unallowed conditions
    841   if (mix->state == MIX_STATE_UNINITIALIZED)
    842     ret = MIX_RESULT_NOT_INIT; // Will not allowed if the state is still UNINITIALIZED
    843   else if ((mix->codecMode != MIX_CODING_DECODE) && (mix->codecMode != MIX_CODING_ENCODE))
    844     ret = MIX_RESULT_WRONGMODE; // This configure is allowed only in DECODE mode.
    845   else if ((mix->streamState != MIX_STREAM_STOPPED) && (mix->streamState != MIX_STREAM_NULL))
    846     ret = MIX_RESULT_WRONG_STATE;
    847 
    848   if (!MIX_SUCCEEDED(ret))
    849   {
    850     // Some check failed. Unlock and return.
    851     _UNLOCK(&mix->controllock);
    852     _UNLOCK(&mix->streamlock);
    853     return ret;
    854   }
    855 
    856   if (audioconfigparams->audio_manager == MIX_AUDIOMANAGER_INTELAUDIOMANAGER) {
    857     mix->useIAM = TRUE;
    858   }
    859   // now configure stream.
    860 
    861   ret = mix_audio_am_unregister(mix, audioconfigparams);
    862 
    863   if (MIX_SUCCEEDED(ret))
    864   {
    865     ret = mix_audio_SST_SET_PARAMS(mix, audioconfigparams);
    866   }
    867 
    868   if (MIX_SUCCEEDED(ret))
    869   {
    870     ret = mix_audio_am_register(mix, audioconfigparams);
    871   }
    872 
    873   if (MIX_SUCCEEDED(ret))
    874   {
    875     mix->state = MIX_STATE_CONFIGURED;
    876   }
    877   else
    878   {
    879     mix->state = MIX_STATE_INITIALIZED;
    880   }
    881 
    882   _UNLOCK(&mix->controllock);
    883   _UNLOCK(&mix->streamlock);
    884 
    885   return ret;
    886 }
    887 
    888 MIX_RESULT mix_audio_get_timestamp_default(MixAudio *mix, guint64 *msecs)
    889 {
    890   MIX_RESULT ret = MIX_RESULT_SUCCESS;
    891 
    892   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    893 
    894   if (!msecs) return MIX_RESULT_NULL_PTR;
    895 
    896   _LOCK(&mix->controllock);
    897 
    898   if (mix->state == MIX_STATE_CONFIGURED)
    899   {
    900     if ((mix->codecMode == MIX_CODING_DECODE) && (MIX_ACP_DECODEMODE(mix->audioconfigparams) == MIX_DECODE_DECODERETURN))
    901     {
    902       ret = MIX_RESULT_WRONGMODE;
    903     }
    904     else {
    905 
    906       unsigned long long ts = 0;
    907       int retVal = 0;
    908 
    909 #ifdef LPESTUB
    910       // For stubbing, just get system clock.
    911       if (MIX_ACP_BITRATE(mix->audioconfigparams) > 0)
    912       {
    913         // use bytes_written and bitrate
    914         // to get times in msec.
    915         ts = mix->bytes_written * 8000 / MIX_ACP_BITRATE(mix->audioconfigparams);
    916       }
    917       else if (mix->ts_last)
    918       {
    919         GTimeVal tval = {0};
    920         g_get_current_time(&tval);
    921         ts = 1000ll * tval.tv_sec + tval.tv_usec / 1000;
    922         ts -= mix->ts_last;
    923         ts += mix->ts_elapsed;
    924       }
    925       else
    926       {
    927         ts = 0;
    928       }
    929 #else
    930       g_debug("Calling SNDRV_SST_STREAM_GET_TSTAMP. fd=%d", mix->fileDescriptor);
    931       ioctl(mix->fileDescriptor, SNDRV_SST_STREAM_GET_TSTAMP, &ts);
    932 #endif
    933 
    934       if (retVal)
    935       {
    936         ret = MIX_RESULT_SYSTEM_ERRNO;
    937         g_debug("_GET_TSTAMP failed. Error:0x%08x", errno);
    938         //ret = MIX_RESULT_FAIL;
    939         mix_audio_debug_dump(mix);
    940       }
    941       else
    942       {
    943         *msecs = ts;
    944         g_debug("_GET_TSTAMP returned %" G_GUINT64_FORMAT, ts);
    945       }
    946     }
    947   }
    948   else
    949     ret = MIX_RESULT_NOT_CONFIGURED;
    950 
    951   _UNLOCK(&mix->controllock);
    952 
    953   return ret;
    954 }
    955 
    956 gboolean mix_audio_AM_Change(MixAudioConfigParams *oldparams, MixAudioConfigParams *newparams)
    957 {
    958   if (g_strcmp0(oldparams->stream_name, newparams->stream_name) == 0) {
    959     return FALSE;
    960   }
    961 
    962   return TRUE;
    963 }
    964 
    965 MIX_RESULT mix_audio_am_unregister(MixAudio *mix, MixAudioConfigParams *audioconfigparams)
    966 {
    967   MIX_RESULT ret = MIX_RESULT_SUCCESS;
    968 
    969   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    970 
    971   if (mix->am_registered && MIX_IS_AUDIOCONFIGPARAMS(mix->audioconfigparams) && MIX_IS_AUDIOCONFIGPARAMS(audioconfigparams))
    972   {
    973     // we have 2 params. let's check
    974     if ((MIX_ACP_DECODEMODE(mix->audioconfigparams) != MIX_ACP_DECODEMODE(audioconfigparams)) ||
    975        mix_audio_AM_Change(mix->audioconfigparams, audioconfigparams)) //TODO: add checking for SST change
    976     {
    977       // decode mode change.
    978       if (mix->amStreamID > 0) {
    979         if (lpe_stream_unregister(mix->amStreamID) != 0) {
    980 	  return MIX_RESULT_FAIL;
    981         }
    982         mix->am_registered = FALSE;
    983       }
    984     }
    985   }
    986 
    987   return ret;
    988 }
    989 
    990 MIX_RESULT mix_audio_am_register(MixAudio *mix, MixAudioConfigParams *audioconfigparams)
    991 {
    992   MIX_RESULT ret = MIX_RESULT_SUCCESS;
    993 
    994   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
    995 
    996   gint32 codec_mode = -1;
    997 
    998   if (mix->codecMode == MIX_CODING_DECODE)
    999     codec_mode = 0;
   1000   else if (mix->codecMode == MIX_CODING_ENCODE)
   1001     codec_mode = 1;
   1002   else
   1003     return MIX_RESULT_FAIL;     // TODO: what to do when fail?
   1004 
   1005 #ifdef AUDIO_MANAGER
   1006   if (audioconfigparams->stream_name == NULL)
   1007     return MIX_RESULT_FAIL;
   1008 
   1009 // if AM is enable, and not_registered, then register
   1010   if (mix->useIAM && !mix->am_registered) {
   1011     gint32 amStreamID = lpe_stream_register(mix->streamID, "music", audioconfigparams->stream_name, codec_mode);
   1012 
   1013     if (amStreamID == -1){
   1014       mix->amStreamID = 0;
   1015         return MIX_RESULT_FAIL;
   1016     }
   1017     else if (amStreamID == -2) {	// -2: Direct render not avail, see AM spec
   1018       mix->amStreamID = 0;
   1019       return MIX_RESULT_DIRECT_NOTAVAIL;
   1020     }
   1021     mix->am_registered = TRUE;
   1022     mix->amStreamID = amStreamID;
   1023   }
   1024 #endif
   1025 
   1026   return ret;
   1027 }
   1028 
   1029 MIX_RESULT mix_audio_capture_encode_default(MixAudio *mix, MixIOVec *iovout, gint iovoutcnt)
   1030 {
   1031   struct iovec *vec;
   1032   gint bytes_read;
   1033 
   1034   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1035 
   1036   // TODO: set count limit
   1037   if (iovoutcnt < 1) {
   1038     return MIX_RESULT_INVALID_COUNT;
   1039   }
   1040 
   1041   if (iovout == NULL)
   1042     return MIX_RESULT_NULL_PTR;
   1043 
   1044   vec = (struct iovec *) g_alloca(sizeof(struct iovec) * iovoutcnt);
   1045   if (!vec) return MIX_RESULT_NO_MEMORY;
   1046 
   1047   gint i;
   1048   for (i=0; i < iovoutcnt; i++)
   1049   {
   1050     vec[i].iov_base = iovout[i].data;
   1051     vec[i].iov_len = iovout[i].size;
   1052   }
   1053 
   1054   mix_log(MIX_AUDIO_COMP, MIX_LOG_LEVEL_INFO, "begin readv()\n");
   1055   bytes_read = readv(mix->fileDescriptor, vec, iovoutcnt);
   1056   mix_log(MIX_AUDIO_COMP, MIX_LOG_LEVEL_INFO, "end readv(), return: %d\n", bytes_read);
   1057   if (bytes_read < 0) { // TODO: should not be 0, but driver return 0 right now
   1058     mix_log(MIX_AUDIO_COMP, MIX_LOG_LEVEL_ERROR, "return: %d\n", bytes_read);
   1059     return MIX_RESULT_FAIL;
   1060   }
   1061 /*
   1062   gint bytes_count=0;
   1063   for (i=0; i < iovoutcnt; i++)
   1064   {
   1065     bytes_count += iovout[i].size;
   1066   }
   1067   iovout[i].size = bytes_read - bytes_count;
   1068 */
   1069   return MIX_RESULT_SUCCESS;
   1070 }
   1071 
   1072 MIX_RESULT mix_audio_get_max_vol_default(MixAudio *mix, gint *maxvol)
   1073 {
   1074   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1075 
   1076   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1077 
   1078   if (!maxvol) return MIX_RESULT_NULL_PTR;
   1079 
   1080   _LOCK(&mix->controllock);
   1081 
   1082   if (!has_FW_INFO)
   1083   {
   1084     ret = mix_audio_FW_INFO(mix);
   1085   }
   1086 
   1087   if (MIX_SUCCEEDED(ret))
   1088   {
   1089     *maxvol = (gint)cur_FW_INFO.pop_info.max_vol;
   1090   }
   1091 
   1092   _UNLOCK(&mix->controllock);
   1093 
   1094   return ret;
   1095 }
   1096 
   1097 
   1098 MIX_RESULT mix_audio_get_min_vol_default(MixAudio *mix, gint *minvol)
   1099 {
   1100   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1101 
   1102   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1103 
   1104   if (!minvol) return MIX_RESULT_NULL_PTR;
   1105 
   1106   _LOCK(&mix->controllock);
   1107 
   1108   if (!has_FW_INFO)
   1109   {
   1110     ret = mix_audio_FW_INFO(mix);
   1111   }
   1112 
   1113   if (MIX_SUCCEEDED(ret))
   1114   {
   1115     *minvol = (gint)cur_FW_INFO.pop_info.min_vol;
   1116   }
   1117 
   1118   _UNLOCK(&mix->controllock);
   1119 
   1120   return ret;
   1121 }
   1122 
   1123 MIX_RESULT mix_audio_get_stream_state_default(MixAudio *mix, MixStreamState *streamState)
   1124 {
   1125   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1126 
   1127   if (!streamState) return MIX_RESULT_NULL_PTR;
   1128 
   1129   _LOCK(&mix->controllock);
   1130 
   1131   if (mix->state != MIX_STATE_CONFIGURED) _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_NOT_CONFIGURED);
   1132 
   1133   // PAUSED_DRAINING is internal state.
   1134   if (mix->streamState == MIX_STREAM_PAUSED_DRAINING)
   1135     *streamState = MIX_STREAM_PAUSED;
   1136   else
   1137     *streamState = mix->streamState;
   1138 
   1139   _UNLOCK(&mix->controllock);
   1140 
   1141   return MIX_RESULT_SUCCESS;
   1142 }
   1143 
   1144 
   1145 MIX_RESULT mix_audio_get_volume_default(MixAudio *mix, gint *currvol, MixVolType type)
   1146 {
   1147   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1148 
   1149   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1150 
   1151   struct snd_sst_vol vol = {0};
   1152 
   1153   if (!currvol) return MIX_RESULT_NULL_PTR;
   1154   if ((type != MIX_VOL_PERCENT) && (type != MIX_VOL_DECIBELS)) return MIX_RESULT_INVALID_PARAM;
   1155 
   1156   _LOCK(&mix->controllock);
   1157 
   1158   if (mix->state != MIX_STATE_CONFIGURED) _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_NOT_CONFIGURED);
   1159 
   1160   vol.stream_id = mix->streamID;
   1161 
   1162   int retVal = 0;
   1163 
   1164 #ifdef LPESTUB
   1165   // Not calling.
   1166 #else
   1167   g_debug("Calling SNDRV_SST_GET_VOL. fd=%d", mix->fileDescriptor);
   1168   retVal = ioctl(mix->fileDescriptor, SNDRV_SST_GET_VOL, &vol);
   1169   g_debug("SNDRV_SST_GET_VOL returned %d. vol=%d", retVal, vol.volume);
   1170 #endif
   1171 
   1172   if (retVal)
   1173   {
   1174     ret = MIX_RESULT_SYSTEM_ERRNO;
   1175     g_debug("_GET_VOL failed. Error:0x%08x", errno);
   1176     mix_audio_debug_dump(mix);
   1177   }
   1178   else
   1179   {
   1180     gint maxvol = 0;
   1181     ret = mix_audio_get_max_vol(mix, &maxvol);
   1182 
   1183     if (MIX_SUCCEEDED(ret))
   1184     {
   1185       if (type == MIX_VOL_PERCENT)
   1186         *currvol = (maxvol!=0)?((vol.volume * 100) / maxvol):0;
   1187       else
   1188         *currvol = vol.volume;
   1189     }
   1190   }
   1191 
   1192   _UNLOCK(&mix->controllock);
   1193 
   1194   return ret;
   1195 }
   1196 
   1197 MIX_RESULT mix_audio_get_mute_default(MixAudio *mix, gboolean* muted)
   1198 {
   1199   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1200   return ret;
   1201 }
   1202 
   1203 MIX_RESULT mix_audio_set_mute_default(MixAudio *mix, gboolean mute)
   1204 {
   1205   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1206 
   1207   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1208 
   1209   struct snd_sst_mute m = { 0 };
   1210 
   1211   if (mute) m.mute = 1;
   1212   else m.mute = 0;
   1213 
   1214   _LOCK(&mix->controllock);
   1215 
   1216   if (mix->state != MIX_STATE_CONFIGURED) _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_NOT_CONFIGURED);
   1217 
   1218   m.stream_id = mix->streamID;
   1219 
   1220   int retVal = 0;
   1221 
   1222 #ifdef LPESTUB
   1223   // Not calling.
   1224 #else
   1225   retVal = ioctl(mix->fileDescriptor, SNDRV_SST_MUTE, &m);
   1226 #endif
   1227 
   1228   if (retVal)
   1229   {
   1230     //ret = MIX_RESULT_FAIL;
   1231     ret = MIX_RESULT_SYSTEM_ERRNO;
   1232     g_debug("_MUTE failed. Error:0x%08x", errno);
   1233     mix_audio_debug_dump(mix);
   1234   }
   1235 
   1236   _UNLOCK(&mix->controllock);
   1237 
   1238   return ret;
   1239 }
   1240 
   1241 MIX_RESULT mix_audio_pause_default(MixAudio *mix)
   1242 {
   1243   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1244 
   1245   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1246 
   1247   _LOCK(&mix->controllock);
   1248 
   1249   if (mix->state != MIX_STATE_CONFIGURED) _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_NOT_CONFIGURED);
   1250 
   1251   if (mix->streamState == MIX_STREAM_PAUSED) _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_SUCCESS);
   1252 
   1253   if ((mix->streamState != MIX_STREAM_PLAYING) && (mix->streamState != MIX_STREAM_DRAINING))
   1254     _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_WRONG_STATE);
   1255 
   1256   int retVal = 0;
   1257 
   1258 #ifdef LPESTUB
   1259   // Not calling
   1260 #else
   1261   g_debug("Calling SNDRV_SST_STREAM_PAUSE. fd=%d", mix->fileDescriptor);
   1262   retVal = ioctl(mix->fileDescriptor, SNDRV_SST_STREAM_PAUSE);
   1263   g_debug("_PAUSE returned %d", retVal);
   1264 #endif
   1265 
   1266   if (retVal)
   1267   {
   1268     if (mix->streamState == MIX_STREAM_DRAINING)
   1269     {
   1270       // if stream state has been DRAINING, DRAIN could become successful during the PAUSE call, but not yet have chance to update streamState since we now hold the lock.
   1271       // In this case, the mix_streamState becomes out-of-sync with the actual playback state. PAUSE failed due to stream already STOPPED but mix->streamState remains at "DRAINING"
   1272       // On the other hand, we can't let DRAIN hold the lock the entire time.
   1273       // We would not know if we fail PAUSE due to DRAINING, or a valid reason.
   1274       // Need a better mechanism to sync DRAINING.
   1275       // DRAINING is not likely problem for resume, as long as the PAUSED state is set when stream is really PAUSED.
   1276       ret = MIX_RESULT_NEED_RETRY;
   1277       g_warning("PAUSE failed while DRAINING. Draining could be just completed. Retry needed.");
   1278     }
   1279     else
   1280     {
   1281       ret = MIX_RESULT_SYSTEM_ERRNO;
   1282       g_debug("_PAUSE failed. Error:0x%08x", errno);
   1283       mix_audio_debug_dump(mix);
   1284     }
   1285   }
   1286   else
   1287   {
   1288     if (mix->streamState == MIX_STREAM_DRAINING)
   1289     {
   1290       mix->streamState = MIX_STREAM_PAUSED_DRAINING;
   1291     }
   1292     else
   1293     {
   1294       mix->streamState = MIX_STREAM_PAUSED;
   1295     }
   1296   }
   1297 
   1298   _UNLOCK(&mix->controllock);
   1299 
   1300 #ifdef LPESTUB
   1301   if (MIX_SUCCEEDED(ret))
   1302   {
   1303     GTimeVal tval = {0};
   1304     g_get_current_time(&tval);
   1305     guint64 ts = 1000ll * tval.tv_sec + tval.tv_usec / 1000;
   1306     mix->ts_elapsed += ts - mix->ts_last;
   1307     mix->ts_last = 0;
   1308   }
   1309 #endif
   1310   return ret;
   1311 }
   1312 
   1313 MIX_RESULT mix_audio_resume_default(MixAudio *mix)
   1314 {
   1315   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1316 
   1317   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1318 
   1319   _LOCK(&mix->controllock);
   1320 
   1321   if (mix->state != MIX_STATE_CONFIGURED) _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_NOT_CONFIGURED);
   1322 
   1323   if ((mix->streamState == MIX_STREAM_PLAYING) || (mix->streamState == MIX_STREAM_DRAINING))
   1324     _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_SUCCESS);
   1325 
   1326   if ((mix->streamState != MIX_STREAM_PAUSED_DRAINING) && (mix->streamState != MIX_STREAM_PAUSED))
   1327     _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_WRONG_STATE);
   1328 
   1329   int retVal = 0;
   1330 
   1331 #ifdef LPESTUB
   1332   // Not calling
   1333 #else
   1334   g_debug("Calling SNDRV_SST_STREAM_RESUME");
   1335   retVal = ioctl(mix->fileDescriptor, SNDRV_SST_STREAM_RESUME);
   1336   g_debug("_STREAM_RESUME returned %d", retVal);
   1337 #endif
   1338 
   1339   if (retVal)
   1340   {
   1341     ret = MIX_RESULT_SYSTEM_ERRNO;
   1342     g_debug("_PAUSE failed. Error:0x%08x", errno);
   1343     mix_audio_debug_dump(mix);
   1344   }
   1345   {
   1346     if (mix->streamState == MIX_STREAM_PAUSED_DRAINING)
   1347       mix->streamState = MIX_STREAM_DRAINING;
   1348     else
   1349       mix->streamState = MIX_STREAM_PLAYING;
   1350   }
   1351 
   1352   _UNLOCK(&mix->controllock);
   1353 
   1354 #ifdef LPESTUB
   1355   if (MIX_SUCCEEDED(ret))
   1356   {
   1357     GTimeVal tval = {0};
   1358     g_get_current_time(&tval);
   1359     guint64 ts = 1000ll * tval.tv_sec + tval.tv_usec / 1000;
   1360     mix->ts_last = ts;
   1361   }
   1362 #endif
   1363 
   1364   return ret;
   1365 }
   1366 
   1367 MIX_RESULT mix_audio_set_volume_default(MixAudio *mix, gint currvol, MixVolType type, gulong msecs, MixVolRamp ramptype)
   1368 {
   1369   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1370 
   1371   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1372 
   1373   struct snd_sst_vol vol = {0};
   1374 
   1375   vol.ramp_duration = msecs;
   1376   vol.ramp_type = ramptype; // TODO: confirm the mappings between Mix and SST.
   1377 
   1378   if (!mix) return MIX_RESULT_NULL_PTR;
   1379 
   1380   if ((type != MIX_VOL_PERCENT) && (type != MIX_VOL_DECIBELS)) return MIX_RESULT_INVALID_PARAM;
   1381 
   1382   _LOCK(&mix->controllock);
   1383 
   1384   if (mix->state != MIX_STATE_CONFIGURED) _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_NOT_CONFIGURED);
   1385 
   1386   vol.stream_id = mix->streamID;
   1387 
   1388   if (type == MIX_VOL_DECIBELS)
   1389   {
   1390     vol.volume = currvol;
   1391   }
   1392   else
   1393   {
   1394     gint maxvol = 0;
   1395     ret = mix_audio_get_max_vol(mix, &maxvol);
   1396 
   1397     if (!maxvol)
   1398       g_critical("Max Vol is 0!");
   1399 
   1400     if (MIX_SUCCEEDED(ret))
   1401     {
   1402       vol.volume = currvol * maxvol / 100;
   1403     }
   1404   }
   1405 
   1406   int retVal = 0;
   1407 
   1408 #ifdef LPESTUB
   1409   // Not calling
   1410 #else
   1411   g_debug("calling SNDRV_SST_SET_VOL vol=%d", vol.volume);
   1412   retVal = ioctl(mix->fileDescriptor, SNDRV_SST_SET_VOL, &vol);
   1413   g_debug("SNDRV_SST_SET_VOL returned %d", retVal);
   1414 #endif
   1415 
   1416   if (retVal)
   1417   {
   1418     ret = MIX_RESULT_SYSTEM_ERRNO;
   1419     g_debug("_SET_VOL failed. Error:0x%08x", errno);
   1420     mix_audio_debug_dump(mix);
   1421   }
   1422 
   1423   _UNLOCK(&mix->controllock);
   1424 
   1425   return ret;
   1426 }
   1427 
   1428 MIX_RESULT mix_audio_FW_INFO(MixAudio *mix)
   1429 {
   1430   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1431 
   1432   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1433 
   1434   _LOCK(&mix->controllock);
   1435 
   1436   // This call always get the fw info.
   1437   int retVal = 0;
   1438 
   1439 #ifdef LPESTUB
   1440   // Not calling.
   1441 #else
   1442   g_debug("calling SNDRV_SST_FW_INFO fd=%d", mix->fileDescriptor);
   1443   retVal = ioctl(mix->fileDescriptor, SNDRV_SST_FW_INFO, &cur_FW_INFO);
   1444   g_debug("SNDRV_SST_FW_INFO returned %d", retVal);
   1445 #endif
   1446 
   1447   if (!retVal)
   1448   {
   1449     has_FW_INFO = TRUE;
   1450   }
   1451   else
   1452   {
   1453     ret = MIX_RESULT_SYSTEM_ERRNO;
   1454     g_debug("_FW_INFO failed. Error:0x%08x", errno);
   1455     mix_audio_debug_dump(mix);
   1456   }
   1457 
   1458   _UNLOCK(&mix->controllock);
   1459 
   1460   return ret;
   1461 }
   1462 
   1463 
   1464 static MIX_RESULT mix_audio_SST_writev(MixAudio *mix, const MixIOVec *iovin, gint iovincnt, guint64 *insize)
   1465 {
   1466   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1467 
   1468   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1469 
   1470 /*
   1471   definition of "struct iovec" used by writev:
   1472   struct iovec {
   1473       void  *iov_base;
   1474       size_t iov_len;
   1475   };
   1476 */
   1477 
   1478   if (!mix) return MIX_RESULT_NULL_PTR;
   1479 
   1480   size_t total_bytes = 0;
   1481   // NOTE: we may want to find a way to avoid this copy.
   1482   struct iovec *in = (struct iovec*)g_alloca(sizeof(struct iovec) * iovincnt);
   1483   if (!in) return MIX_RESULT_NO_MEMORY;
   1484 
   1485   int i;
   1486   for (i=0;i<iovincnt;i++)
   1487   {
   1488     in[i].iov_base = (void*)iovin[i].data;
   1489     in[i].iov_len = (size_t)iovin[i].size;
   1490     total_bytes += in[i].iov_len;
   1491   }
   1492 
   1493   ssize_t written = 0;
   1494 
   1495 #ifdef LPESTUB
   1496   gulong wait_time = 0; //wait time in second.
   1497   if (MIX_ACP_BITRATE(mix->audioconfigparams) > 0)
   1498   {
   1499     wait_time = total_bytes*8*1000*1000/MIX_ACP_BITRATE(mix->audioconfigparams);
   1500     // g_debug("To wait %lu usec for writev() to simulate blocking\n", wait_time);
   1501   }
   1502   GTimer *timer = g_timer_new();
   1503   g_timer_start(timer);
   1504 
   1505   g_debug("calling writev(fd=%d)", mix->fileDescriptor);
   1506   written = writev(mix->fileDescriptor, in, iovincnt);
   1507   if (written >= 0) mix->bytes_written += written;
   1508   g_debug("writev() returned %d. Total %" G_GUINT64_FORMAT, written, mix->bytes_written);
   1509   /* Now since writing to file rarely block, we put timestamp there to block.*/
   1510   g_timer_stop(timer);
   1511   gulong elapsed = 0;
   1512   g_timer_elapsed(timer, &elapsed);
   1513   g_timer_destroy(timer);
   1514   // g_debug("writev() returned in %lu usec\n", elapsed);
   1515   if ((MIX_ACP_BITRATE(mix->audioconfigparams) > 0) && (wait_time > elapsed))
   1516   {
   1517     wait_time -= elapsed;
   1518     g_usleep(wait_time);
   1519   }
   1520 #else
   1521   g_debug("calling writev(fd=%d) with %d", mix->fileDescriptor, total_bytes);
   1522   written = writev(mix->fileDescriptor, in, iovincnt);
   1523   if (written > 0) mix->bytes_written += written;
   1524   g_debug("writev() returned %d. Total %" G_GUINT64_FORMAT, written, mix->bytes_written);
   1525 #endif
   1526 
   1527   if (written < 0)
   1528   {
   1529     ret = MIX_RESULT_SYSTEM_ERRNO;
   1530     g_debug("writev() failed. Error:0x%08x", errno);
   1531   }
   1532   else
   1533   {
   1534     // guranttee written is positive value before sign extending it.
   1535     if (insize) *insize = (guint64)written;
   1536     if (written != total_bytes)
   1537     {
   1538         g_warning("writev() wrote only %d out of %d", written, total_bytes);
   1539     }
   1540   }
   1541 
   1542   return ret;
   1543 }
   1544 
   1545 static MIX_RESULT mix_audio_SST_STREAM_DECODE(MixAudio *mix, const MixIOVec *iovin, gint iovincnt, guint64 *insize, MixIOVec *iovout, gint iovoutcnt, guint64 *outsize)
   1546 {
   1547   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1548   int retVal = 0;
   1549 
   1550   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1551 
   1552   if ((iovout == NULL) || (iovoutcnt <= 0))
   1553   {
   1554     g_critical("Wrong mode. Please report a bug...");
   1555     return MIX_RESULT_NULL_PTR;
   1556   }
   1557 
   1558   g_message("Input entries=%d. Output entries=%d", iovincnt, iovoutcnt);
   1559 
   1560   struct snd_sst_buff_entry *ientries = NULL;
   1561   struct snd_sst_buff_entry *oentries = NULL;
   1562 
   1563   ientries = (struct snd_sst_buff_entry*)g_alloca(sizeof(struct snd_sst_buff_entry) * iovincnt);
   1564   oentries = (struct snd_sst_buff_entry*)g_alloca(sizeof(struct snd_sst_buff_entry) * iovoutcnt);
   1565 
   1566   if (!ientries || !oentries) return MIX_RESULT_NO_MEMORY;
   1567 
   1568   struct snd_sst_dbufs dbufs = {0};
   1569 
   1570   struct snd_sst_buffs ibuf = {0};
   1571   struct snd_sst_buffs obuf = {0};
   1572 
   1573   ibuf.entries = iovincnt;
   1574   ibuf.type = SST_BUF_USER;
   1575   ibuf.buff_entry = ientries;
   1576 
   1577   obuf.entries = iovoutcnt;
   1578   obuf.type = SST_BUF_USER;
   1579   obuf.buff_entry = oentries;
   1580 
   1581   dbufs.ibufs = &ibuf;
   1582   dbufs.obufs = &obuf;
   1583 
   1584   int i = 0;
   1585   for (i=0;i<iovincnt;i++)
   1586   {
   1587     ientries[i].size = (unsigned long)iovin[i].size;
   1588     ientries[i].buffer = (void *)iovin[i].data;
   1589     g_debug("Creating in entry#%d, size=%u", i, ientries[i].size);
   1590   }
   1591 
   1592   for (i=0;i<iovoutcnt;i++)
   1593   {
   1594     oentries[i].size = (unsigned long)iovout[i].size;
   1595     oentries[i].buffer = (void *)iovout[i].data;
   1596     g_debug("Creating out entry#%d, size=%u", i, oentries[i].size);
   1597   }
   1598 
   1599 #ifdef LPESTUB
   1600   size_t total_bytes = 0;
   1601   // NOTE: we may want to find a way to avoid this copy.
   1602   struct iovec *in = (struct iovec*)g_alloca(sizeof(struct iovec) * iovincnt);
   1603   if (iovincnt>1)
   1604   {
   1605     for (i=0;i<iovincnt-1;i++)
   1606     {
   1607       in[i].iov_base = (void*)iovin[i].data;
   1608       in[i].iov_len = (size_t)iovin[i].size;
   1609       total_bytes += in[i].iov_len;
   1610     }
   1611     in[i].iov_base = (void*)iovin[i].data;
   1612     in[i].iov_len = (size_t)iovin[i].size/2;
   1613     total_bytes += in[i].iov_len;
   1614   }
   1615   else
   1616   {
   1617     for (i=0;i<iovincnt;i++)
   1618     {
   1619       in[i].iov_base = (void*)iovin[i].data;
   1620       in[i].iov_len = (size_t)iovin[i].size;
   1621       total_bytes += in[i].iov_len;
   1622     }
   1623   }
   1624   ssize_t written = 0;
   1625 
   1626   g_debug("calling stub STREAM_DECODE (writev) (fd=%d)", mix->fileDescriptor);
   1627   written = writev(mix->fileDescriptor, in, iovincnt);
   1628   if (written >= 0)
   1629   {
   1630     mix->bytes_written += written;
   1631     dbufs.output_bytes_produced = written;
   1632     dbufs.input_bytes_consumed = written;
   1633   }
   1634   g_debug("stub STREAM_DECODE (writev) returned %d. Total %" G_GUINT64_FORMAT, written, mix->bytes_written);
   1635 #else
   1636   g_debug("calling SNDRV_SST_STREAM_DECODE fd=%d", mix->fileDescriptor);
   1637   retVal = ioctl(mix->fileDescriptor, SNDRV_SST_STREAM_DECODE, &dbufs);
   1638   g_debug("SNDRV_SST_STREAM_DECODE returned %d", retVal);
   1639 #endif
   1640 
   1641   if (retVal)
   1642   {
   1643     ret = MIX_RESULT_SYSTEM_ERRNO;
   1644     g_debug("_STREAM_DECODE failed. Error:0x%08x", errno);
   1645     mix_audio_debug_dump(mix);
   1646   }
   1647   else
   1648   {
   1649     if (insize) *insize = dbufs.input_bytes_consumed;
   1650     if (outsize) *outsize = dbufs.output_bytes_produced;
   1651     g_message("consumed=%" G_GUINT64_FORMAT " produced=%" G_GUINT64_FORMAT, dbufs.input_bytes_consumed, dbufs.output_bytes_produced);
   1652   }
   1653 
   1654   return ret;
   1655 }
   1656 
   1657 // Starting interface
   1658 //MIX_RESULT mix_audio_get_version(guint* major, guint *minor);
   1659 
   1660 MIX_RESULT mix_audio_initialize(MixAudio *mix, MixCodecMode mode, MixAudioInitParams *aip, MixDrmParams *drminitparams)
   1661 {
   1662   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1663 
   1664   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1665 
   1666   mix_log(MIX_AUDIO_COMP, MIX_LOG_LEVEL_VERBOSE, "mix_audio_initialize\n");
   1667 
   1668   if (!klass->initialize)
   1669     return MIX_RESULT_FAIL;     // TODO: add more descriptive error
   1670 
   1671 #ifdef AUDIO_MANAGER
   1672   if (dbus_init() < 0) {
   1673     mix_log(MIX_AUDIO_COMP, MIX_LOG_LEVEL_ERROR, "Failed to connect to dbus\n");
   1674 // commented out, gracefully exit right now
   1675 //    return MIX_RESULT_FAIL;     // TODO: add more descriptive error
   1676   }
   1677 #endif
   1678 
   1679   return klass->initialize(mix, mode, aip, drminitparams);
   1680 }
   1681 
   1682 MIX_RESULT mix_audio_configure(MixAudio *mix, MixAudioConfigParams *audioconfigparams, MixDrmParams *drmparams)
   1683 {
   1684   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1685 
   1686   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1687 
   1688   if (!klass->configure)
   1689 	return MIX_RESULT_FAIL;
   1690 
   1691   return klass->configure(mix, audioconfigparams, drmparams);
   1692 }
   1693 
   1694 MIX_RESULT mix_audio_decode(MixAudio *mix, const MixIOVec *iovin, gint iovincnt, guint64 *insize, MixIOVec *iovout, gint iovoutcnt, guint64 *outsize)
   1695 {
   1696   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1697 
   1698   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1699 
   1700   if (!klass->decode)
   1701     return MIX_RESULT_FAIL;
   1702 
   1703   return klass->decode(mix, iovin, iovincnt, insize, iovout, iovoutcnt, outsize);
   1704 }
   1705 
   1706 MIX_RESULT mix_audio_capture_encode(MixAudio *mix, MixIOVec *iovout, gint iovoutcnt)
   1707 {
   1708   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1709 
   1710   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1711 
   1712   if (!klass->capture_encode)
   1713     return MIX_RESULT_FAIL;
   1714 
   1715   return klass->capture_encode(mix, iovout, iovoutcnt);
   1716 }
   1717 
   1718 MIX_RESULT mix_audio_start(MixAudio *mix)
   1719 {
   1720   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1721 
   1722   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1723 
   1724   if (!klass->start)
   1725     return MIX_RESULT_FAIL;
   1726 
   1727   return klass->start(mix);
   1728 }
   1729 
   1730 MIX_RESULT mix_audio_stop_drop(MixAudio *mix)
   1731 {
   1732   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1733 
   1734   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1735 
   1736   if (!klass->stop_drop)
   1737     return MIX_RESULT_FAIL;
   1738 
   1739   return klass->stop_drop(mix);
   1740 }
   1741 
   1742 MIX_RESULT mix_audio_stop_drain(MixAudio *mix)
   1743 {
   1744   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1745 
   1746   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1747 
   1748   if (!klass->stop_drain)
   1749     return MIX_RESULT_FAIL;
   1750 
   1751   return klass->stop_drain(mix);
   1752 }
   1753 
   1754 MIX_RESULT mix_audio_pause(MixAudio *mix)
   1755 {
   1756   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1757 
   1758   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1759 
   1760   if (!klass->pause)
   1761     return MIX_RESULT_FAIL;
   1762 
   1763   return klass->pause(mix);
   1764 }
   1765 
   1766 MIX_RESULT mix_audio_resume(MixAudio *mix)
   1767 {
   1768   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1769 
   1770   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1771 
   1772   if (!klass->resume)
   1773     return MIX_RESULT_FAIL;
   1774 
   1775   return klass->resume(mix);
   1776 }
   1777 
   1778 MIX_RESULT mix_audio_get_timestamp(MixAudio *mix, guint64 *msecs)
   1779 {
   1780   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1781 
   1782   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1783 
   1784   if (!klass->get_timestamp)
   1785     return MIX_RESULT_FAIL;
   1786 
   1787   return klass->get_timestamp(mix, msecs);
   1788 }
   1789 
   1790 MIX_RESULT mix_audio_get_mute(MixAudio *mix, gboolean* muted)
   1791 {
   1792   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1793 
   1794   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1795 
   1796   if (!klass->get_mute)
   1797     return MIX_RESULT_FAIL;
   1798 
   1799   return klass->get_mute(mix, muted);
   1800 }
   1801 
   1802 MIX_RESULT mix_audio_set_mute(MixAudio *mix, gboolean mute)
   1803 {
   1804   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1805 
   1806   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1807 
   1808   if (!klass->set_mute)
   1809     return MIX_RESULT_FAIL;
   1810 
   1811   return klass->set_mute(mix, mute);
   1812 }
   1813 
   1814 MIX_RESULT mix_audio_get_max_vol(MixAudio *mix, gint *maxvol)
   1815 {
   1816   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1817 
   1818   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1819 
   1820   if (!klass->get_max_vol)
   1821     return MIX_RESULT_FAIL;
   1822 
   1823   return klass->get_max_vol(mix, maxvol);
   1824 }
   1825 
   1826 MIX_RESULT mix_audio_get_min_vol(MixAudio *mix, gint *minvol)
   1827 {
   1828   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1829 
   1830   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1831 
   1832   if (!klass->get_min_vol)
   1833     return MIX_RESULT_FAIL;
   1834 
   1835   return klass->get_min_vol(mix, minvol);
   1836 }
   1837 
   1838 MIX_RESULT mix_audio_get_volume(MixAudio *mix, gint *currvol, MixVolType type)
   1839 {
   1840   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1841 
   1842   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1843 
   1844   if (!klass->get_volume)
   1845     return MIX_RESULT_FAIL;
   1846 
   1847   return klass->get_volume(mix, currvol, type);
   1848 }
   1849 
   1850 MIX_RESULT mix_audio_set_volume(MixAudio *mix, gint currvol, MixVolType type, gulong msecs, MixVolRamp ramptype)
   1851 {
   1852   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1853 
   1854   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1855 
   1856   if (!klass->set_volume)
   1857     return MIX_RESULT_FAIL;
   1858 
   1859   return klass->set_volume(mix, currvol, type, msecs, ramptype);
   1860 }
   1861 
   1862 MIX_RESULT mix_audio_deinitialize(MixAudio *mix)
   1863 {
   1864   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1865 
   1866   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1867 
   1868   if (!klass->deinitialize)
   1869     return MIX_RESULT_FAIL;
   1870 
   1871   return klass->deinitialize(mix);
   1872 }
   1873 
   1874 MIX_RESULT mix_audio_get_stream_state(MixAudio *mix, MixStreamState *streamState)
   1875 {
   1876   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1877 
   1878   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1879 
   1880   if (!klass->get_stream_state)
   1881     return MIX_RESULT_FAIL;
   1882 
   1883   return klass->get_stream_state(mix, streamState);
   1884 }
   1885 
   1886 MIX_RESULT mix_audio_get_state(MixAudio *mix, MixState *state)
   1887 {
   1888   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   1889 
   1890   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1891 
   1892   if (!klass->get_state)
   1893     return MIX_RESULT_FAIL;
   1894 
   1895   return klass->get_state(mix, state);
   1896 }
   1897 
   1898 MIX_RESULT mix_audio_is_am_available_default(MixAudio *mix, MixAudioManager am, gboolean *avail)
   1899 {
   1900   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   1901 
   1902   if (avail)
   1903     *avail = FALSE;
   1904   else
   1905     ret = MIX_RESULT_NULL_PTR;
   1906 
   1907   return ret;
   1908 }
   1909 
   1910 MIX_RESULT mix_audio_is_am_available(MixAudio *mix, MixAudioManager am, gboolean *avail)
   1911 {
   1912   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   1913 
   1914   if (!klass->is_am_available)
   1915     return MIX_RESULT_FAIL;
   1916 
   1917   return klass->is_am_available(mix, am, avail);
   1918 }
   1919 
   1920 const gchar* dbgstr_UNKNOWN="UNKNOWN";
   1921 
   1922 static const gchar* _mix_stream_state_get_name (MixStreamState s)
   1923 {
   1924   static const gchar *MixStreamStateNames[] = {
   1925     "MIX_STREAM_NULL",
   1926     "MIX_STREAM_STOPPED",
   1927     "MIX_STREAM_PLAYING",
   1928     "MIX_STREAM_PAUSED",
   1929     "MIX_STREAM_DRAINING",
   1930     "MIX_STREAM_PAUSED_DRAINING",
   1931     "MIX_STREAM_INTERNAL_LAST"
   1932   };
   1933 
   1934   const gchar *ret = dbgstr_UNKNOWN;
   1935 
   1936   if (s < sizeof(MixStreamStateNames)/sizeof(MixStreamStateNames[0]))
   1937   {
   1938     ret = MixStreamStateNames[s];
   1939   }
   1940 
   1941   return ret;
   1942 }
   1943 
   1944 static const gchar* _mix_state_get_name(MixState s)
   1945 {
   1946   static const gchar* MixStateNames[] = {
   1947     "MIX_STATE_NULL",
   1948     "MIX_STATE_UNINITIALIZED",
   1949     "MIX_STATE_INITIALIZED",
   1950     "MIX_STATE_CONFIGURED",
   1951     "MIX_STATE_LAST"
   1952   };
   1953 
   1954   const gchar *ret = dbgstr_UNKNOWN;
   1955 
   1956   if (s < sizeof(MixStateNames)/sizeof(MixStateNames[0]))
   1957   {
   1958     ret = MixStateNames[s];
   1959   }
   1960 
   1961   return ret;
   1962 }
   1963 
   1964 static const gchar* _mix_codec_mode_get_name(MixCodecMode s)
   1965 {
   1966   static const gchar* MixCodecModeNames[] = {
   1967     "MIX_CODING_INVALID",
   1968     "MIX_CODING_ENCODE",
   1969     "MIX_CODING_DECODE",
   1970     "MIX_CODING_LAST"
   1971   };
   1972 
   1973   const gchar *ret = dbgstr_UNKNOWN;
   1974 
   1975   if (s < sizeof(MixCodecModeNames)/sizeof(MixCodecModeNames[0]))
   1976   {
   1977     ret = MixCodecModeNames[s];
   1978   }
   1979 
   1980   return ret;
   1981 }
   1982 
   1983 static const gchar* _mix_device_state_get_name(MixDeviceState s)
   1984 {
   1985   static const gchar* MixDeviceStateNames[] = {
   1986     "MIX_AUDIO_DEV_CLOSED",
   1987     "MIX_AUDIO_DEV_OPENED",
   1988     "MIX_AUDIO_DEV_ALLOCATED"
   1989   };
   1990 
   1991   const gchar *ret = dbgstr_UNKNOWN;
   1992 
   1993   if (s < sizeof(MixDeviceStateNames)/sizeof(MixDeviceStateNames[0]))
   1994   {
   1995     ret = MixDeviceStateNames[s];
   1996   }
   1997 
   1998   return ret;
   1999 }
   2000 
   2001 void mix_audio_debug_dump(MixAudio *mix)
   2002 {
   2003   const gchar* prefix="MixAudio:";
   2004 
   2005   if (!MIX_IS_AUDIO(mix))
   2006   {
   2007     g_debug("%s Not a valid MixAudio object.", prefix);
   2008     return;
   2009   }
   2010 
   2011   g_debug("%s streamState(%s)", prefix, _mix_stream_state_get_name(mix->streamState));
   2012   g_debug("%s encoding(%s)", prefix, mix->encoding?mix->encoding:dbgstr_UNKNOWN);
   2013   g_debug("%s fileDescriptor(%d)", prefix, mix->fileDescriptor);
   2014   g_debug("%s state(%s)", prefix, _mix_state_get_name(mix->state));
   2015   g_debug("%s codecMode(%s)", prefix, _mix_codec_mode_get_name(mix->codecMode));
   2016 
   2017   // Private members
   2018   g_debug("%s streamID(%d)", prefix, mix->streamID);
   2019   //GStaticRecMutex streamlock; // lock that must be acquired to invoke stream method.
   2020   //GStaticRecMutex controllock; // lock that must be acquired to call control function.
   2021   if (MIX_IS_AUDIOCONFIGPARAMS(mix->audioconfigparams))
   2022   {
   2023     // TODO: print audioconfigparams
   2024   }
   2025   else
   2026   {
   2027     g_debug("%s audioconfigparams(NULL)", prefix);
   2028   }
   2029 
   2030   g_debug("%s deviceState(%s)", prefix, _mix_device_state_get_name(mix->deviceState));
   2031 
   2032   g_debug("%s ts_last(%" G_GUINT64_FORMAT ")", prefix, mix->ts_last);
   2033   g_debug("%s ts_elapsed(%" G_GUINT64_FORMAT ")", prefix, mix->ts_elapsed);
   2034   g_debug("%s bytes_written(%" G_GUINT64_FORMAT ")", prefix, mix->bytes_written);
   2035 
   2036   return;
   2037 }
   2038 
   2039 MIX_RESULT mix_audio_get_output_configuration(MixAudio *mix, MixAudioConfigParams **audioconfigparams)
   2040 {
   2041   if (G_UNLIKELY(!mix)) return MIX_RESULT_NULL_PTR;
   2042 
   2043   MixAudioClass *klass = MIX_AUDIO_GET_CLASS(mix);
   2044 
   2045   if (!klass->get_output_configuration)
   2046     return MIX_RESULT_FAIL;
   2047 
   2048   return klass->get_output_configuration(mix, audioconfigparams);
   2049 }
   2050 
   2051 MIX_RESULT mix_audio_get_output_configuration_default(MixAudio *mix, MixAudioConfigParams **audioconfigparams)
   2052 {
   2053   MIX_RESULT ret = MIX_RESULT_SUCCESS;
   2054   struct snd_sst_get_stream_params stream_params = {{0}};
   2055   MixAudioConfigParams *p = NULL;
   2056   int retVal = 0;
   2057 
   2058   if (G_UNLIKELY(!mix || !audioconfigparams)) return MIX_RESULT_NULL_PTR;
   2059 
   2060   _LOCK(&mix->controllock);
   2061 
   2062   if (mix->state <= MIX_STATE_UNINITIALIZED) _UNLOCK_RETURN(&mix->controllock, MIX_RESULT_NOT_INIT);
   2063 
   2064 #ifdef LPESTUB
   2065 #else
   2066   // Check only if we are initialized.
   2067     g_debug("Calling SNDRV_SST_STREAM_GET_PARAMS. fd=%d", mix->fileDescriptor);
   2068     retVal = ioctl(mix->fileDescriptor, SNDRV_SST_STREAM_GET_PARAMS, &stream_params);
   2069     g_debug("_GET_PARAMS returned %d", retVal);
   2070 #endif
   2071 
   2072   _UNLOCK(&mix->controllock);
   2073 
   2074   if (retVal)
   2075   {
   2076       ret = MIX_RESULT_SYSTEM_ERRNO;
   2077       g_debug("Failed to GET_PARAMS. errno:0x%08x. %s\n", errno, strerror(errno));
   2078   }
   2079   else
   2080   {
   2081       p = mix_sst_params_to_acp(&stream_params);
   2082       *audioconfigparams = p;
   2083   }
   2084 
   2085   return ret;
   2086 }
   2087 
   2088 MIX_RESULT mix_audio_get_stream_byte_decoded(MixAudio *mix, guint64 *byte)
   2089 {
   2090     return MIX_RESULT_NOT_SUPPORTED;
   2091 }
   2092 
   2093