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 */ 92static 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 100typedef enum { 101 MIX_STREAM_PAUSED_DRAINING = MIX_STREAM_LAST, 102 MIX_STREAM_INTERNAL_LAST 103} MixStreamStateInternal; 104 105 106MIX_RESULT mix_audio_initialize_default(MixAudio *mix, MixCodecMode mode, MixAudioInitParams *aip, MixDrmParams *drminitparams); 107MIX_RESULT mix_audio_configure_default(MixAudio *mix, MixAudioConfigParams *audioconfigparams, MixDrmParams *drmparams); 108MIX_RESULT mix_audio_decode_default(MixAudio *mix, const MixIOVec *iovin, gint iovincnt, guint64 *insize, MixIOVec *iovout, gint iovoutcnt, guint64 *outsize); 109MIX_RESULT mix_audio_capture_encode_default(MixAudio *mix, MixIOVec *iovout, gint iovoutcnt); 110MIX_RESULT mix_audio_start_default(MixAudio *mix); 111MIX_RESULT mix_audio_stop_drop_default(MixAudio *mix); 112MIX_RESULT mix_audio_stop_drain_default(MixAudio *mix); 113MIX_RESULT mix_audio_pause_default(MixAudio *mix); 114MIX_RESULT mix_audio_resume_default(MixAudio *mix); 115MIX_RESULT mix_audio_get_timestamp_default(MixAudio *mix, guint64 *msecs); 116MIX_RESULT mix_audio_set_mute_default(MixAudio *mix, gboolean mute); 117MIX_RESULT mix_audio_get_mute_default(MixAudio *mix, gboolean* muted); 118MIX_RESULT mix_audio_get_max_vol_default(MixAudio *mix, gint *maxvol); 119MIX_RESULT mix_audio_get_min_vol_default(MixAudio *mix, gint *minvol); 120MIX_RESULT mix_audio_get_volume_default(MixAudio *mix, gint *currvol, MixVolType type); 121MIX_RESULT mix_audio_set_volume_default(MixAudio *mix, gint currvol, MixVolType type, gulong msecs, MixVolRamp ramptype); 122MIX_RESULT mix_audio_deinitialize_default(MixAudio *mix); 123MIX_RESULT mix_audio_get_stream_state_default(MixAudio *mix, MixStreamState *streamState); 124MIX_RESULT mix_audio_get_state_default(MixAudio *mix, MixState *state); 125MIX_RESULT mix_audio_is_am_available_default(MixAudio *mix, MixAudioManager am, gboolean *avail); 126MIX_RESULT mix_audio_get_output_configuration_default(MixAudio *mix, MixAudioConfigParams **audioconfigparams); 127 128static gboolean g_IAM_available = FALSE; 129MIX_RESULT mix_audio_am_unregister(MixAudio *mix, MixAudioConfigParams *audioconfigparams); 130MIX_RESULT mix_audio_am_register(MixAudio *mix, MixAudioConfigParams *audioconfigparams); 131MIX_RESULT mix_audio_AM_Change(MixAudioConfigParams *oldparams, MixAudioConfigParams *newparams); 132 133static void mix_audio_finalize(GObject *obj); 134G_DEFINE_TYPE (MixAudio, mix_audio, G_TYPE_OBJECT); 135 136static gboolean has_FW_INFO = FALSE; 137static struct snd_sst_fw_info cur_FW_INFO = {{0}}; 138 139static MIX_RESULT mix_audio_FW_INFO(MixAudio *mix); 140static MIX_RESULT mix_audio_SST_SET_PARAMS(MixAudio *mix, MixAudioConfigParams *params); 141static MIX_RESULT mix_audio_SST_writev(MixAudio *mix, const MixIOVec *iovin, gint iovincnt, guint64 *insize); 142static MIX_RESULT mix_audio_SST_STREAM_DECODE(MixAudio *mix, const MixIOVec *iovin, gint iovincnt, guint64 *insize, MixIOVec *iovout, gint iovoutcnt, guint64 *outsize); 143static void mix_audio_debug_dump(MixAudio *mix); 144 145static guint g_log_handler=0; 146static 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*/ 154void mix_acp_print_params(MixAudioConfigParams *obj); 155 156static 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 185void _mix_aip_initialize (void); 186 187static 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 255static 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 282MixAudio *mix_audio_new(void) 283{ 284 MixAudio *ret = g_object_new(MIX_TYPE_AUDIO, NULL); 285 286 return ret; 287} 288 289void 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 317MixAudio *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 324MIX_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 410gboolean 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 417gboolean 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 */ 433MIX_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 539MIX_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 552MIX_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 572MIX_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 613MIX_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 655MIX_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 745MIX_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 812MIX_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 824MIX_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 888MIX_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 956gboolean 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 965MIX_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 990MIX_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 1029MIX_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 1072MIX_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 1098MIX_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 1123MIX_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 1145MIX_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 1197MIX_RESULT mix_audio_get_mute_default(MixAudio *mix, gboolean* muted) 1198{ 1199 MIX_RESULT ret = MIX_RESULT_SUCCESS; 1200 return ret; 1201} 1202 1203MIX_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 1241MIX_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 1313MIX_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 1367MIX_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 1428MIX_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 1464static 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 1545static 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 1660MIX_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 1682MIX_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 1694MIX_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 1706MIX_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 1718MIX_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 1730MIX_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 1742MIX_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 1754MIX_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 1766MIX_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 1778MIX_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 1790MIX_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 1802MIX_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 1814MIX_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 1826MIX_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 1838MIX_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 1850MIX_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 1862MIX_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 1874MIX_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 1886MIX_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 1898MIX_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 1910MIX_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 1920const gchar* dbgstr_UNKNOWN="UNKNOWN"; 1921 1922static 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 1944static 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 1964static 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 1983static 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 2001void 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 2039MIX_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 2051MIX_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 2088MIX_RESULT mix_audio_get_stream_byte_decoded(MixAudio *mix, guint64 *byte) 2089{ 2090 return MIX_RESULT_NOT_SUPPORTED; 2091} 2092 2093