/* compress stream operations */
static void sst_compr_fragment_elapsed(void *arg)
{
	struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;

	pr_debug("fragment elapsed by driver\n");
	if (cstream)
		snd_compr_fragment_elapsed(cstream);
}
Esempio n. 2
0
static int compr_event_handler(uint32_t cmd, uint32_t size, void* priv)
{
    struct runtime_data *prtd = priv;
    struct snd_compr_runtime *runtime = prtd->cstream->runtime;
    u64 bytes_available;
    int ret;

    pr_debug("%s: event handler cmd(%x)\n", __func__, cmd);

#ifdef AUDIO_PERF
    prtd->start_time[ISR_T] = sched_clock();
#endif
    switch(cmd) {
    case INTR_CREATED:
        pr_debug("%s: offload instance is created\n", __func__);
        break;
    case INTR_DECODED:
        spin_lock(&prtd->lock);

        /* update copied total bytes */
        prtd->copied_total += size;
        prtd->byte_offset += size;
        if (prtd->byte_offset >= runtime->buffer_size)
            prtd->byte_offset -= runtime->buffer_size;

        snd_compr_fragment_elapsed(prtd->cstream);

        if (!atomic_read(&prtd->start) &&
                runtime->state != SNDRV_PCM_STATE_PAUSED) {
            /* Writes must be restarted from _copy() */
            pr_err("%s: write_done received while not started(%d)",
                   __func__, runtime->state);
            spin_unlock(&prtd->lock);
            return -EIO;
        }

        bytes_available = prtd->received_total -
                          prtd->copied_total;

        pr_debug("%s: current free bufsize(%llu)\n", __func__,
                 runtime->buffer_size - bytes_available);

        if (bytes_available < runtime->fragment_size) {
            pr_debug("%s: WRITE_DONE Insufficient data to send.(avail:%llu)\n",
                     __func__, bytes_available);
        }
        spin_unlock(&prtd->lock);
        break;
    case INTR_FLUSH:
        prtd->stop_ack = 1;
        wake_up(&prtd->flush_wait);
        break;
    case INTR_PAUSED:
        ret = compr_dai_cmd(prtd, cmd);
        if (ret)
            pr_err("%s: compr_dai_cmd fail(%d)\n", __func__, ret);
        break;
    case INTR_EOS:
        if (atomic_read(&prtd->eos)) {
            if (prtd->copied_total != prtd->received_total)
                pr_err("%s: EOS is not sync!(%llu/%llu)\n", __func__,
                       prtd->copied_total, prtd->received_total);
            /* ALSA Framework callback to notify drain complete */
            snd_compr_drain_notify(prtd->cstream);
            atomic_set(&prtd->eos, 0);
            pr_info("%s: DATA_CMD_EOS wake up\n", __func__);
        }
        break;
    case INTR_DESTROY:
        prtd->exit_ack = 1;
        wake_up(&prtd->exit_wait);
        break;
    default:
        pr_err("%s: unknown command(%x)\n", __func__, cmd);
        break;
    }
#ifdef AUDIO_PERF
    prtd->end_time[ISR_T] = sched_clock();
    prtd->total_time[ISR_T] +=
        prtd->end_time[ISR_T] - prtd->start_time[ISR_T];
#endif
    return 0;
}
static void compr_event_handler(uint32_t opcode,
		uint32_t token, uint32_t *payload, void *priv)
{
	struct msm_compr_audio *prtd = priv;
	struct snd_compr_stream *cstream = prtd->cstream;
	struct audio_client *ac = prtd->audio_client;
	uint32_t chan_mode = 0;
	uint32_t sample_rate = 0;
	int bytes_available, stream_id;

	pr_debug("%s opcode =%08x\n", __func__, opcode);
	switch (opcode) {
	case ASM_DATA_EVENT_WRITE_DONE_V2:
		spin_lock(&prtd->lock);

		if (payload[3]) {
			pr_err("WRITE FAILED w/ err 0x%x !, paddr 0x%x"
			       " byte_offset = %d, copied_total = %d, token = %d\n",
			       payload[3],
			       payload[0],
			       prtd->byte_offset, prtd->copied_total, token);
			atomic_set(&prtd->start, 0);
		} else {
			pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2 offset %d, length %d\n",
				 prtd->byte_offset, token);
		}

		prtd->byte_offset += token;
		prtd->copied_total += token;
		if (prtd->byte_offset >= prtd->buffer_size)
			prtd->byte_offset -= prtd->buffer_size;

		snd_compr_fragment_elapsed(cstream);

		if (!atomic_read(&prtd->start)) {
			/* Writes must be restarted from _copy() */
			pr_debug("write_done received while not started, treat as xrun");
			atomic_set(&prtd->xrun, 1);
			spin_unlock(&prtd->lock);
			break;
		}

		bytes_available = prtd->bytes_received - prtd->copied_total;
		if (bytes_available < cstream->runtime->fragment_size) {
			pr_debug("WRITE_DONE Insufficient data to send. break out\n");
			atomic_set(&prtd->xrun, 1);

			if (prtd->last_buffer)
				prtd->last_buffer = 0;
			if (atomic_read(&prtd->drain)) {
				pr_debug("wake up on drain\n");
				prtd->drain_ready = 1;
				wake_up(&prtd->drain_wait);
				atomic_set(&prtd->drain, 0);
			}
		} else if ((bytes_available == cstream->runtime->fragment_size)
			   && atomic_read(&prtd->drain)) {
			prtd->last_buffer = 1;
			msm_compr_send_buffer(prtd);
			prtd->last_buffer = 0;
		} else
			msm_compr_send_buffer(prtd);

		spin_unlock(&prtd->lock);
		break;
	case ASM_DATA_EVENT_RENDERED_EOS:
		pr_debug("ASM_DATA_CMDRSP_EOS\n");
		spin_lock(&prtd->lock);
		if (atomic_read(&prtd->eos) &&
		    !prtd->gapless_state.set_next_stream_id) {
			pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
			prtd->cmd_ack = 1;
			wake_up(&prtd->eos_wait);
		}
		atomic_set(&prtd->eos, 0);
		stream_id = ac->stream_id^1; /*prev stream */
		if (prtd->gapless_state.set_next_stream_id &&
		    prtd->gapless_state.stream_opened[stream_id]) {
			q6asm_stream_cmd_nowait(prtd->audio_client,
						CMD_CLOSE, stream_id);
			atomic_set(&prtd->close, 1);
			prtd->gapless_state.stream_opened[stream_id] = 0;
			prtd->gapless_state.set_next_stream_id = false;
		}
		spin_unlock(&prtd->lock);
		break;
	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
	case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: {
		pr_debug("ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY\n");
		chan_mode = payload[1] >> 16;
		sample_rate = payload[2] >> 16;
		if (prtd && (chan_mode != prtd->num_channels ||
				sample_rate != prtd->sample_rate)) {
			prtd->num_channels = chan_mode;
			prtd->sample_rate = sample_rate;
		}
	}
	case APR_BASIC_RSP_RESULT: {
		switch (payload[0]) {
		case ASM_SESSION_CMD_RUN_V2:
			/* check if the first buffer need to be sent to DSP */
			pr_debug("ASM_SESSION_CMD_RUN_V2\n");

			spin_lock(&prtd->lock);
			/* FIXME: A state is a much better way of dealing with this */
			if (!prtd->copied_total) {
				bytes_available = prtd->bytes_received - prtd->copied_total;
				if (bytes_available < cstream->runtime->fragment_size) {
					pr_debug("CMD_RUN_V2 Insufficient data to send. break out\n");
					atomic_set(&prtd->xrun, 1);
				} else
					msm_compr_send_buffer(prtd);
			}
			spin_unlock(&prtd->lock);
			break;
		case ASM_STREAM_CMD_FLUSH:
			pr_debug("ASM_STREAM_CMD_FLUSH\n");
			prtd->cmd_ack = 1;
			wake_up(&prtd->flush_wait);
			break;
		case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
			pr_debug("ASM_DATA_CMD_REMOVE_INITIAL_SILENCE\n");
			break;
		case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
			pr_debug("ASM_DATA_CMD_REMOVE_TRAILING_SILENCE\n");
			break;
		case ASM_STREAM_CMD_CLOSE:
			pr_debug("ASM_DATA_CMD_CLOSE\n");
			if (atomic_read(&prtd->close) &&
			    atomic_read(&prtd->wait_on_close)) {
				prtd->cmd_ack = 1;
				wake_up(&prtd->close_wait);
			}
			atomic_set(&prtd->close, 0);
			break;
		default:
			break;
		}
		break;
	}
	case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
		pr_debug("ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3\n");
		break;
	case RESET_EVENTS:
		pr_err("Received reset events CB, move to error state");
		spin_lock(&prtd->lock);
		snd_compr_fragment_elapsed(cstream);
		prtd->copied_total = prtd->bytes_received;
		atomic_set(&prtd->error, 1);
		spin_unlock(&prtd->lock);
		break;
	default:
		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
		break;
	}
}