static gboolean gst_tinyalsa_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec) { GstTinyalsaSink *sink = GST_TINYALSA_SINK (asink); struct pcm_config config = { 0, }; struct pcm_params *params = NULL; int period_size_min, period_size_max; int periods_min, periods_max; pcm_config_from_spec (&config, spec); GST_DEBUG_OBJECT (sink, "Requesting %u periods of %u frames", config.period_count, config.period_size); params = pcm_params_get (sink->card, sink->device, PCM_OUT); if (!params) GST_ERROR_OBJECT (sink, "Could not get PCM params"); period_size_min = pcm_params_get_min (params, PCM_PARAM_PERIOD_SIZE); period_size_max = pcm_params_get_max (params, PCM_PARAM_PERIOD_SIZE); periods_min = pcm_params_get_min (params, PCM_PARAM_PERIODS); periods_max = pcm_params_get_max (params, PCM_PARAM_PERIODS); pcm_params_free (params); /* Snap period size/count to the permitted range */ config.period_size = CLAMP (config.period_size, period_size_min, period_size_max); config.period_count = CLAMP (config.period_count, periods_min, periods_max); /* mutex with getcaps */ GST_OBJECT_LOCK (sink); sink->pcm = pcm_open (sink->card, sink->device, PCM_OUT | PCM_NORESTART, &config); GST_OBJECT_UNLOCK (sink); if (!sink->pcm || !pcm_is_ready (sink->pcm)) { GST_ERROR_OBJECT (sink, "Could not open device: %s", pcm_get_error (sink->pcm)); goto fail; } if (pcm_prepare (sink->pcm) < 0) { GST_ERROR_OBJECT (sink, "Could not prepare device: %s", pcm_get_error (sink->pcm)); goto fail; } spec->segsize = pcm_frames_to_bytes (sink->pcm, config.period_size); spec->segtotal = config.period_count; GST_DEBUG_OBJECT (sink, "Configured for %u periods of %u frames", config.period_count, config.period_size); return TRUE; fail: if (sink->pcm) pcm_close (sink->pcm); return FALSE; }
static GstCaps * gst_tinyalsa_sink_getcaps (GstBaseSink * bsink, GstCaps * filter) { GstTinyalsaSink *sink = GST_TINYALSA_SINK (bsink); GstCaps *caps = NULL; GValue formats = { 0, }; GValue format = { 0, }; struct pcm_params *params = NULL; struct pcm_mask *mask; int rate_min, rate_max, channels_min, channels_max; guint16 m; GST_DEBUG_OBJECT (sink, "Querying caps"); GST_OBJECT_LOCK (sink); if (sink->cached_caps) { GST_DEBUG_OBJECT (sink, "Returning cached caps"); caps = gst_caps_ref (sink->cached_caps); goto done; } if (sink->pcm) { /* We can't query the device while it's open, so return current caps */ caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (bsink)); goto done; } params = pcm_params_get (sink->card, sink->device, PCM_OUT); if (!params) { GST_ERROR_OBJECT (sink, "Could not get PCM params"); goto done; } mask = pcm_params_get_mask (params, PCM_PARAM_FORMAT); m = (mask->bits[1] << 8) | mask->bits[0]; if (!(m & SNDRV_PCM_FORMAT_ANY)) { GST_ERROR_OBJECT (sink, "Could not find any supported format"); goto done; } caps = gst_caps_new_empty_simple ("audio/x-raw"); g_value_init (&formats, GST_TYPE_LIST); g_value_init (&format, G_TYPE_STRING); if (m & (1 << SNDRV_PCM_FORMAT_S8)) { g_value_set_static_string (&format, "S8"); gst_value_list_prepend_value (&formats, &format); } if (m & (1 << SNDRV_PCM_FORMAT_S16_LE)) { g_value_set_static_string (&format, "S16LE"); gst_value_list_prepend_value (&formats, &format); } if (m & (1 << SNDRV_PCM_FORMAT_S24_LE)) { g_value_set_static_string (&format, "S24_32LE"); gst_value_list_prepend_value (&formats, &format); } if (m & (1 << SNDRV_PCM_FORMAT_S32_LE)) { g_value_set_static_string (&format, "S32LE"); gst_value_list_prepend_value (&formats, &format); } gst_caps_set_value (caps, "format", &formats); g_value_unset (&format); g_value_unset (&formats); /* This is a bit of a lie, since the device likely only supports some * standard rates in this range. We should probably filter the range to * those, standard audio rates but even that isn't guaranteed to be accurate. */ rate_min = pcm_params_get_min (params, PCM_PARAM_RATE); rate_max = pcm_params_get_max (params, PCM_PARAM_RATE); if (rate_min == rate_max) gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate_min, NULL); else gst_caps_set_simple (caps, "rate", GST_TYPE_INT_RANGE, rate_min, rate_max, NULL); channels_min = pcm_params_get_min (params, PCM_PARAM_CHANNELS); channels_max = pcm_params_get_max (params, PCM_PARAM_CHANNELS); if (channels_min == channels_max) gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels_min, NULL); else gst_caps_set_simple (caps, "channels", GST_TYPE_INT_RANGE, channels_min, channels_max, NULL); gst_caps_replace (&sink->cached_caps, caps); done: GST_OBJECT_UNLOCK (sink); GST_DEBUG_OBJECT (sink, "Got caps %" GST_PTR_FORMAT, caps); if (caps && filter) { GstCaps *intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (caps); caps = intersection; } if (params) pcm_params_free (params); return caps; }
int main(int argc, char **argv) { unsigned int device = 0; unsigned int card = 0; int i; if (argc < 3) { fprintf(stderr, "Usage: %s -D card -d device\n", argv[0]); return 1; } /* parse command line arguments */ argv += 1; while (*argv) { if (strcmp(*argv, "-D") == 0) { argv++; if (*argv) card = atoi(*argv); } if (strcmp(*argv, "-d") == 0) { argv++; if (*argv) device = atoi(*argv); } if (*argv) argv++; } printf("Info for card %u, device %u:\n", card, device); for (i = 0; i < 2; i++) { struct pcm_params *params; struct pcm_mask *m; unsigned int min; unsigned int max; printf("\nPCM %s:\n", i == 0 ? "out" : "in"); params = pcm_params_get(card, device, i == 0 ? PCM_OUT : PCM_IN); if (params == NULL) { printf("Device does not exist.\n"); continue; } m = pcm_params_get_mask(params, PCM_PARAM_ACCESS); if (m) { /* bitmask, refer to SNDRV_PCM_ACCESS_*, generally interleaved */ printf(" Access:\t%#08x\n", m->bits[0]); } m = pcm_params_get_mask(params, PCM_PARAM_FORMAT); if (m) { /* bitmask, refer to: SNDRV_PCM_FORMAT_* */ unsigned j, k, count = 0; const unsigned bitcount = sizeof(m->bits[0]) * 8; /* we only check first two format masks (out of 8) - others are zero. */ printf(" Format[0]:\t%#08x\n", m->bits[0]); printf(" Format[1]:\t%#08x\n", m->bits[1]); /* print friendly format names, if they exist */ for (k = 0; k < 2; ++k) { for (j = 0; j < bitcount; ++j) { const char *name; if (m->bits[k] & (1 << j)) { name = pcm_get_format_name(j + k*bitcount); if (name) { if (count++ == 0) { printf(" Format Name:\t"); } else { printf (", "); } printf("%s", name); } } } } if (count) { printf("\n"); } } m = pcm_params_get_mask(params, PCM_PARAM_SUBFORMAT); if (m) { /* bitmask, should be 1: SNDRV_PCM_SUBFORMAT_STD */ printf(" Subformat:\t%#08x\n", m->bits[0]); } min = pcm_params_get_min(params, PCM_PARAM_RATE); max = pcm_params_get_max(params, PCM_PARAM_RATE); printf(" Rate:\tmin=%uHz\tmax=%uHz\n", min, max); min = pcm_params_get_min(params, PCM_PARAM_CHANNELS); max = pcm_params_get_max(params, PCM_PARAM_CHANNELS); printf(" Channels:\tmin=%u\t\tmax=%u\n", min, max); min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS); max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS); printf(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max); min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE); max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE); printf(" Period size:\tmin=%u\t\tmax=%u\n", min, max); min = pcm_params_get_min(params, PCM_PARAM_PERIODS); max = pcm_params_get_max(params, PCM_PARAM_PERIODS); printf("Period count:\tmin=%u\t\tmax=%u\n", min, max); pcm_params_free(params); } return 0; }
status_t AudioALSAPlaybackHandlerSphDL::open() { ALOGD("+%s(), mDevice = 0x%x", __FUNCTION__, mStreamAttributeSource->output_devices); // debug pcm dump OpenPCMDump(LOG_TAG); int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmI2S0Dl1Playback); int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmI2S0Dl1Playback); ALOGD("AudioALSAPlaybackHandlerSphDL::open() pcmindex = %d", pcmindex); ListPcmDriver(cardindex, pcmindex); struct pcm_params *params; params = pcm_params_get(cardindex, pcmindex, PCM_OUT); if (params == NULL) { ALOGD("Device does not exist.\n"); } mStreamAttributeTarget.buffer_size = pcm_params_get_max(params, PCM_PARAM_BUFFER_BYTES); ALOGD("buffersizemax = %d", mStreamAttributeTarget.buffer_size); pcm_params_free(params); // HW attribute config // TODO(Harvey): query this mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_16_BIT; mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_IN_MONO; mStreamAttributeTarget.num_channels = android_audio_legacy::AudioSystem::popCount(mStreamAttributeTarget.audio_channel_mask); mStreamAttributeTarget.sample_rate = mStreamAttributeSource->sample_rate; // same as source stream // HW pcm config mConfig.channels = mStreamAttributeTarget.num_channels; mConfig.rate = mStreamAttributeTarget.sample_rate; // Buffer size: 1536(period_size) * 2(ch) * 4(byte) * 2(period_count) = 24 kb mConfig.period_count = 4; //mConfig.period_size = (0x4000/(mConfig.channels*mConfig.period_count))/((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4); mConfig.period_size = 512; mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format); mConfig.start_threshold = 0; mConfig.stop_threshold = 0; mConfig.silence_threshold = 0; ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d", __FUNCTION__, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format); // post processing initPostProcessing(); #if defined(MTK_SPEAKER_MONITOR_SUPPORT) unsigned int fc, bw; int th; if (mAudioFilterManagerHandler) { AudioALSASpeakerMonitor::getInstance()->GetFilterParam(&fc, &bw, &th); ALOGD("%s(), fc %d bw %d, th %d", __FUNCTION__, fc, bw, th); mAudioFilterManagerHandler->setSpkFilterParam(fc, bw, th); } #endif // SRC initBliSrc(); // bit conversion initBitConverter(); // open pcm driver openPcmDriver(pcmindex); //Echo reference path if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Dl1_MD_Echo_Ref_Switch"), "On")) { ALOGE("Error: Audio_Dl1_MD_Echo_Ref_Switch invalid value"); } // open codec driver // Don't startoutputDevice here, let speech driver to open. mHardwareResourceManager->startOutputDevice(mStreamAttributeSource->output_devices, mStreamAttributeTarget.sample_rate); ALOGD("-%s()", __FUNCTION__); return NO_ERROR; }
status_t AudioALSAPlaybackHandlerOffload::open() { ALOGD("+%s(), mDevice = 0x%x", __FUNCTION__, mStreamAttributeSource->output_devices); ALOGD("%s(), mStreamAttributeSource: format = %d",__FUNCTION__, mStreamAttributeSource->audio_format); AudioAutoTimeoutLock _l(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock()); // debug pcm dump OpenPCMDump(LOG_TAG); // acquire pmic clk mHardwareResourceManager->EnableAudBufClk(true); //doug to check //HpImpeDanceDetect(); //doug to check #if 1 int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmDl1Meida); int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmDl1Meida); ALOGD("AudioALSAPlaybackHandlerOffload::open() pcmindex = %d", pcmindex); ListPcmDriver(cardindex, pcmindex); struct pcm_params *params; params = pcm_params_get(cardindex, pcmindex, PCM_OUT); if (params == NULL) { ALOGD("Device does not exist.\n"); } mStreamAttributeTarget.buffer_size = pcm_params_get_max(params, PCM_PARAM_BUFFER_BYTES); ALOGD("%s buffersizemax = %d", __FUNCTION__, mStreamAttributeTarget.buffer_size); pcm_params_free(params); #endif //mStreamAttributeTarget.buffer_size = 32768; //#ifdef PLAYBACK_USE_24BITS_ONLY //mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_32_BIT; mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_8_24_BIT; //mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_16_BIT; //#else // mStreamAttributeTarget.audio_format = (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT) ? AUDIO_FORMAT_PCM_8_24_BIT : AUDIO_FORMAT_PCM_16_BIT; //#endif mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO; mStreamAttributeTarget.num_channels = android_audio_legacy::AudioSystem::popCount(mStreamAttributeTarget.audio_channel_mask); mStreamAttributeTarget.sample_rate = ChooseTargetSampleRate(mStreamAttributeSource->sample_rate); // HW pcm config mConfig.channels = mStreamAttributeTarget.num_channels; mConfig.rate = mStreamAttributeTarget.sample_rate; // Buffer size: 1536(period_size) * 2(ch) * 4(byte) * 2(period_count) = 24 kb mConfig.period_count = 2; mConfig.period_size = (mStreamAttributeTarget.buffer_size / (mConfig.channels * mConfig.period_count)) / ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4); mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format); mConfig.start_threshold = 0; mConfig.stop_threshold = 0; mConfig.silence_threshold = 0; ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d", __FUNCTION__, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format); mComprConfig.codec = (struct snd_codec*)malloc(sizeof(struct snd_codec)); if(mComprConfig.codec == NULL) ALOGE("%s(), allocate mComprConfig.codec fail"); mComprConfig.fragments = 1024; mComprConfig.fragment_size = 8192; //mComprConfig.fragment_size = mStreamAttributeTarget.buffer_size; mComprConfig.codec->sample_rate = mStreamAttributeTarget.sample_rate; mComprConfig.codec->reserved[0] = mConfig.period_size; mComprConfig.codec->reserved[1] = mComprConfig.fragments*mComprConfig.fragment_size; if(mConfig.format == PCM_FORMAT_S16_LE) mComprConfig.codec->format = SNDRV_PCM_FORMAT_S16_LE; else mComprConfig.codec->format = SNDRV_PCM_FORMAT_S32_LE; mComprConfig.codec->id = SND_AUDIOCODEC_MP3; mComprConfig.codec->ch_in = 2; mComprConfig.codec->ch_out = 2; //init decoder mDecHandler = AudioDecHandlerCreate(); if(mDecHandler == NULL) { ALOGE("+%s(), DecHandler create fail", __FUNCTION__); ASSERT(false); return -ENOSYS; } if(!mDecHandler->InitAudioDecoder()) { ALOGE("+%s(), Decoder IP init fail", __FUNCTION__); ASSERT(false); return -ENOSYS; } // post processing initPostProcessing(); // SRC initBliSrc(); // bit conversion initBitConverter(); initDataPending(); // disable lowjitter mode //doug to check SetLowJitterMode(true, mStreamAttributeTarget.sample_rate); openComprDriver(23); if( compress_set_gapless_metadata(mComprStream, &offload_stream.offload_mdata) != 0) ALOGE("%s(), compress_set_gapless_metadata() error= %s", __FUNCTION__, compress_get_error(mComprStream)); mHardwareResourceManager->startOutputDevice(mStreamAttributeSource->output_devices, mStreamAttributeTarget.sample_rate); offload_stream.tmpBuffer = (void*)malloc(mComprConfig.fragment_size); mWritebytes = mComprConfig.fragment_size; list_init(&offload_stream.offload_cmd_list); int ret = pthread_mutex_init(&offload_stream.offload_mutex, NULL); if (ret != 0) { ALOGE("%s, Failed to initialize Mutex!", __FUNCTION__); ASSERT(false); return -ENOSYS; } ret = pthread_cond_init(&offload_stream.offload_cond, NULL); if (ret != 0) { ALOGE("%s, Failed to initialize Cond!", __FUNCTION__); ASSERT(false); return -ENOSYS; } threadExit = false; ret = pthread_create(&offload_stream.offload_pthread, NULL, &offload_threadloop, this); if (ret != 0) { ALOGE("%s() create thread OffloadWrite fail!!", __FUNCTION__); ASSERT(false); return -ENOSYS; } usleep(1 * 1000); ALOGD("-%s()", __FUNCTION__); return NO_ERROR; }
static int validate_input_hardware_params(struct stream_in *in) { struct audio_device *adev = in->dev; struct pcm_params *params; unsigned int min; unsigned int max; params = pcm_params_get(adev->card, adev->device, PCM_IN); if (params == NULL) { ALOGW("Device does not exist.\n"); return -1; } /* always open the device with min capabilities if * input params are not supported */ min = pcm_params_get_min(params, PCM_PARAM_RATE); max = pcm_params_get_max(params, PCM_PARAM_RATE); ALOGI("hw supported Rate:\tmin=%uHz\tmax=%uHz\n", min, max); if((in->pcm_config.rate < min) || (in->pcm_config.rate > max)) { in->pcm_config.rate = min; } min = pcm_params_get_min(params, PCM_PARAM_CHANNELS); max = pcm_params_get_max(params, PCM_PARAM_CHANNELS); ALOGI("hw supported Channels:\tmin=%u\t\tmax=%u\n", min, max); if((in->pcm_config.channels < min) || (in->pcm_config.channels > max)) { in->pcm_config.channels = min; } min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS); max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS); ALOGI("hw supported Sample bits:\tmin=%u\t\tmax=%u\n", min, max); unsigned int bits_per_sample = format_to_bits(in->pcm_config.format); if((bits_per_sample < min) || (bits_per_sample > max)) { bits_per_sample = min; } in->pcm_config.format = bits_to_format(bits_per_sample); min = pcm_params_get_min(params, PCM_PARAM_PERIODS); max = pcm_params_get_max(params, PCM_PARAM_PERIODS); ALOGI("hw supported period_count:\tmin=%u\t\tmax=%u\n", min, max); if((in->pcm_config.period_count < min) || (in->pcm_config.period_count > max)) { in->pcm_config.period_count = min; } min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE); max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE); ALOGI("hw supported period_size:\tmin=%u\t\tmax=%u\n", min, max); if((in->pcm_config.period_size < min) || (in->pcm_config.period_size > max)) { in->pcm_config.period_size = min; } ALOGV("%s :: Exit supported params \ \r \t channels = %d, \ \r \t rate = %d, \ \r \t period_size = %d, \ \r \t period_count = %d, \ \r \t format = %d", __func__, in->pcm_config.channels,in->pcm_config.rate, in->pcm_config.period_size,in->pcm_config.period_count, in->pcm_config.format); pcm_params_free(params); return 0; }