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;
}
Exemple #3
0
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;

}