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 Intel’s 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 
mix_audio_init(MixAudio * self)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 
mix_audio_class_init(MixAudioClass * klass)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 
mix_audio_log(const gchar * log_domain,GLogLevelFlags log_level,const gchar * message,gpointer user_data)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 
mix_audio_new(void)282 MixAudio *mix_audio_new(void)
283 {
284   MixAudio *ret = g_object_new(MIX_TYPE_AUDIO, NULL);
285 
286   return ret;
287 }
288 
mix_audio_finalize(GObject * obj)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 
mix_audio_ref(MixAudio * mix)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 
mix_audio_initialize_default(MixAudio * mix,MixCodecMode mode,MixAudioInitParams * aip,MixDrmParams * drminitparams)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 
mix_audio_am_is_available(void)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 
mix_audio_base_am_is_enabled(MixAudio * mix)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  */
mix_audio_SST_SET_PARAMS(MixAudio * mix,MixAudioConfigParams * params)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 
mix_audio_get_state_default(MixAudio * mix,MixState * state)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 
mix_audio_decode_default(MixAudio * mix,const MixIOVec * iovin,gint iovincnt,guint64 * insize,MixIOVec * iovout,gint iovoutcnt,guint64 * outsize)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 
mix_audio_deinitialize_default(MixAudio * mix)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 
mix_audio_stop_drop_default(MixAudio * mix)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 
mix_audio_stop_drain_default(MixAudio * mix)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 
mix_audio_start_default(MixAudio * mix)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 
mix_audio_get_version(guint * major,guint * minor)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 
mix_audio_configure_default(MixAudio * mix,MixAudioConfigParams * audioconfigparams,MixDrmParams * drmparams)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 
mix_audio_get_timestamp_default(MixAudio * mix,guint64 * msecs)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 
mix_audio_AM_Change(MixAudioConfigParams * oldparams,MixAudioConfigParams * newparams)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 
mix_audio_am_unregister(MixAudio * mix,MixAudioConfigParams * audioconfigparams)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 
mix_audio_am_register(MixAudio * mix,MixAudioConfigParams * audioconfigparams)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 
mix_audio_capture_encode_default(MixAudio * mix,MixIOVec * iovout,gint iovoutcnt)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 
mix_audio_get_max_vol_default(MixAudio * mix,gint * maxvol)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 
mix_audio_get_min_vol_default(MixAudio * mix,gint * minvol)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 
mix_audio_get_stream_state_default(MixAudio * mix,MixStreamState * streamState)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 
mix_audio_get_volume_default(MixAudio * mix,gint * currvol,MixVolType type)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 
mix_audio_get_mute_default(MixAudio * mix,gboolean * muted)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 
mix_audio_set_mute_default(MixAudio * mix,gboolean mute)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 
mix_audio_pause_default(MixAudio * mix)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 
mix_audio_resume_default(MixAudio * mix)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 
mix_audio_set_volume_default(MixAudio * mix,gint currvol,MixVolType type,gulong msecs,MixVolRamp ramptype)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 
mix_audio_FW_INFO(MixAudio * mix)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 
mix_audio_SST_writev(MixAudio * mix,const MixIOVec * iovin,gint iovincnt,guint64 * insize)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 
mix_audio_SST_STREAM_DECODE(MixAudio * mix,const MixIOVec * iovin,gint iovincnt,guint64 * insize,MixIOVec * iovout,gint iovoutcnt,guint64 * outsize)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 
mix_audio_initialize(MixAudio * mix,MixCodecMode mode,MixAudioInitParams * aip,MixDrmParams * drminitparams)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 
mix_audio_configure(MixAudio * mix,MixAudioConfigParams * audioconfigparams,MixDrmParams * drmparams)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 
mix_audio_decode(MixAudio * mix,const MixIOVec * iovin,gint iovincnt,guint64 * insize,MixIOVec * iovout,gint iovoutcnt,guint64 * outsize)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 
mix_audio_capture_encode(MixAudio * mix,MixIOVec * iovout,gint iovoutcnt)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 
mix_audio_start(MixAudio * mix)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 
mix_audio_stop_drop(MixAudio * mix)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 
mix_audio_stop_drain(MixAudio * mix)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 
mix_audio_pause(MixAudio * mix)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 
mix_audio_resume(MixAudio * mix)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 
mix_audio_get_timestamp(MixAudio * mix,guint64 * msecs)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 
mix_audio_get_mute(MixAudio * mix,gboolean * muted)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 
mix_audio_set_mute(MixAudio * mix,gboolean mute)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 
mix_audio_get_max_vol(MixAudio * mix,gint * maxvol)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 
mix_audio_get_min_vol(MixAudio * mix,gint * minvol)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 
mix_audio_get_volume(MixAudio * mix,gint * currvol,MixVolType type)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 
mix_audio_set_volume(MixAudio * mix,gint currvol,MixVolType type,gulong msecs,MixVolRamp ramptype)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 
mix_audio_deinitialize(MixAudio * mix)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 
mix_audio_get_stream_state(MixAudio * mix,MixStreamState * streamState)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 
mix_audio_get_state(MixAudio * mix,MixState * state)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 
mix_audio_is_am_available_default(MixAudio * mix,MixAudioManager am,gboolean * avail)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 
mix_audio_is_am_available(MixAudio * mix,MixAudioManager am,gboolean * avail)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 
_mix_stream_state_get_name(MixStreamState s)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 
_mix_state_get_name(MixState s)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 
_mix_codec_mode_get_name(MixCodecMode s)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 
_mix_device_state_get_name(MixDeviceState s)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 
mix_audio_debug_dump(MixAudio * mix)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 
mix_audio_get_output_configuration(MixAudio * mix,MixAudioConfigParams ** audioconfigparams)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 
mix_audio_get_output_configuration_default(MixAudio * mix,MixAudioConfigParams ** audioconfigparams)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 
mix_audio_get_stream_byte_decoded(MixAudio * mix,guint64 * byte)2088 MIX_RESULT mix_audio_get_stream_byte_decoded(MixAudio *mix, guint64 *byte)
2089 {
2090     return MIX_RESULT_NOT_SUPPORTED;
2091 }
2092 
2093