static enum audiotap_status audio_get_pulse(struct audiotap *audiotap, uint32_t *pulse, uint32_t *raw_pulse){ while(!audiotap->terminated && !audiotap->has_flushed){ uint32_t done_now; enum audiotap_status error; uint32_t numframes; done_now=tapenc_get_pulse(audiotap->tapenc, (int32_t*)audiotap->buffer, audiotap->bufroom, raw_pulse); audiotap->buffer += done_now * sizeof(int32_t); audiotap->bufroom -= done_now; if(*raw_pulse > 0){ *pulse = convert_samples(audiotap, *raw_pulse); return AUDIOTAP_OK; } error = audiotap->audio2tap_functions->set_buffer(audiotap->priv, (int32_t*)audiotap->bufstart, sizeof(audiotap->bufstart) / sizeof(int32_t), &numframes); if (error != AUDIOTAP_OK) return error; if (numframes == 0){ *raw_pulse = tapenc_flush(audiotap->tapenc); *pulse = convert_samples(audiotap, *raw_pulse); audiotap->has_flushed=1; return AUDIOTAP_OK; } audiotap->buffer = audiotap->bufstart; audiotap->bufroom = numframes; } return audiotap->terminated ? AUDIOTAP_INTERRUPTED : AUDIOTAP_EOF; }
qint64 ALSAWriter::write(const QByteArray &arr) { if (!readyWrite()) return 0; const int samples = arr.size() / sizeof(float); const int to_write = samples / channels; const int bytes = samples * sample_size; if (int_samples.size() < bytes) int_samples.resize(bytes); switch (sample_size) { case 4: convert_samples((const float *)arr.constData(), samples, (qint32 *)int_samples.constData(), mustSwapChn ? channels : 0); break; case 2: convert_samples((const float *)arr.constData(), samples, (qint16 *)int_samples.constData(), mustSwapChn ? channels : 0); break; case 1: convert_samples((const float *)arr.constData(), samples, (qint8 *)int_samples.constData(), mustSwapChn ? channels : 0); break; } switch (snd_pcm_state(snd)) { case SND_PCM_STATE_XRUN: if (!snd_pcm_prepare(snd)) { const int silence = snd_pcm_avail(snd) - to_write; if (silence > 0) { QByteArray silenceArr(silence * channels * sample_size, 0); snd_pcm_writei(snd, silenceArr.constData(), silence); } } break; case SND_PCM_STATE_PAUSED: snd_pcm_pause(snd, false); break; default: break; } int ret = snd_pcm_writei(snd, int_samples.constData(), to_write); if (ret < 0 && ret != -EPIPE && snd_pcm_recover(snd, ret, false)) { QMPlay2Core.logError("ALSA :: " + tr("Playback error")); err = true; return 0; } return arr.size(); }
/** * Read one audio frame from the input file, decode, convert and store * it in the FIFO buffer. * @param fifo Buffer used for temporary storage * @param input_format_context Format context of the input file * @param input_codec_context Codec context of the input file * @param output_codec_context Codec context of the output file * @param resampler_context Resample context for the conversion * @param[out] finished Indicates whether the end of file has * been reached and all data has been * decoded. If this flag is false, * there is more data to be decoded, * i.e., this function has to be called * again. * @return Error code (0 if successful) */ int Transcode::read_decode_convert_and_store(AVAudioFifo *fifo, AVFormatContext *input_format_context, AVCodecContext *input_codec_context, AVCodecContext *output_codec_context, SwrContext *resampler_context, int *finished) { /* Temporary storage of the input samples of the frame read from the file. */ AVFrame *input_frame = NULL; /* Temporary storage for the converted input samples. */ uint8_t **converted_input_samples = NULL; int data_present; int ret = AVERROR_EXIT; /* Initialize temporary storage for one input frame. */ if (init_input_frame(&input_frame)) goto cleanup; /* Decode one frame worth of audio samples. */ if (decode_audio_frame(input_frame, input_format_context, input_codec_context, &data_present, finished)) goto cleanup; /* If we are at the end of the file and there are no more samples * in the decoder which are delayed, we are actually finished. * This must not be treated as an error. */ if (*finished && !data_present) { ret = 0; goto cleanup; } /* If there is decoded data, convert and store it. */ if (data_present) { /* Initialize the temporary storage for the converted input samples. */ if (init_converted_samples(&converted_input_samples, output_codec_context, input_frame->nb_samples)) goto cleanup; /* Convert the input samples to the desired output sample format. * This requires a temporary storage provided by converted_input_samples. */ if (convert_samples((const uint8_t**)input_frame->extended_data, converted_input_samples, input_frame->nb_samples, resampler_context)) goto cleanup; /* Add the converted input samples to the FIFO buffer for later processing. */ if (add_samples_to_fifo(fifo, converted_input_samples, input_frame->nb_samples)) goto cleanup; ret = 0; } ret = 0; cleanup: if (converted_input_samples) { av_freep(&converted_input_samples[0]); free(converted_input_samples); } av_frame_free(&input_frame); return ret; }
int AudioDecoder::decodeAudio(AVPacket& input_packet, AVPacket& outPacket) { ELOG_DEBUG("decoding input packet, size %d", input_packet.size); AVFrame* input_frame; init_frame(&input_frame); int data_present; int error = avcodec_decode_audio4(input_codec_context, input_frame, &data_present,&input_packet); if (error < 0) { ELOG_DEBUG("decoding error %s", get_error_text(error)); return error; } if (data_present <= 0) { ELOG_DEBUG("data not present"); return 0; } // resample /** Initialize the temporary storage for the converted input samples. */ uint8_t **converted_input_samples = NULL; if (init_converted_samples(&converted_input_samples, output_codec_context, input_frame->nb_samples)) { ELOG_DEBUG("init_converted_samples fails"); return 0; } /** * Convert the input samples to the desired output sample format. * This requires a temporary storage provided by converted_input_samples */ if (convert_samples((const uint8_t**)input_frame->extended_data, converted_input_samples,input_frame->nb_samples, resample_context)) { ELOG_WARN("convert_samples failed!!"); return 0; } /** Add converted input samples to the FIFO buffer for later processing. */ if (add_samples_to_fifo(fifo, converted_input_samples, input_frame->nb_samples)) { ELOG_WARN("add_samples to fifo failed !!"); } outPacket.pts = input_packet.pts; // meanwhile, encode; package return load_encode(outPacket); }
int ff_convert_dither(DitherContext *c, AudioData *dst, AudioData *src) { int ret; AudioData *flt_data; /* output directly to dst if it is planar */ if (dst->sample_fmt == AV_SAMPLE_FMT_S16P) c->s16_data = dst; else { /* make sure s16_data is large enough for the output */ ret = ff_audio_data_realloc(c->s16_data, src->nb_samples); if (ret < 0) return ret; } if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) { /* make sure flt_data is large enough for the input */ ret = ff_audio_data_realloc(c->flt_data, src->nb_samples); if (ret < 0) return ret; flt_data = c->flt_data; /* convert input samples to fltp and scale to s16 range */ ret = ff_audio_convert(c->ac_in, flt_data, src); if (ret < 0) return ret; } else { flt_data = src; } /* check alignment and padding constraints */ if (c->method != AV_RESAMPLE_DITHER_TRIANGULAR_NS) { int ptr_align = FFMIN(flt_data->ptr_align, c->s16_data->ptr_align); int samples_align = FFMIN(flt_data->samples_align, c->s16_data->samples_align); int aligned_len = FFALIGN(src->nb_samples, c->ddsp.samples_align); if (!(ptr_align % c->ddsp.ptr_align) && samples_align >= aligned_len) { c->quantize = c->ddsp.quantize; c->samples_align = c->ddsp.samples_align; } else { c->quantize = quantize_c; c->samples_align = 1; } } ret = convert_samples(c, (int16_t **)c->s16_data->data, (float * const *)flt_data->data, src->channels, src->nb_samples); if (ret < 0) return ret; c->s16_data->nb_samples = src->nb_samples; /* interleave output to dst if needed */ if (dst->sample_fmt == AV_SAMPLE_FMT_S16) { ret = ff_audio_convert(c->ac_out, dst, c->s16_data); if (ret < 0) return ret; } else c->s16_data = NULL; return 0; }
// //========================================================================= // // This is used when --ifile is specified in order to read data from file // instead of using an RTLSDR device // void readDataFromFile(void) { int eof = 0; struct timespec next_buffer_delivery; void *readbuf; int bytes_per_sample = 0; switch (Modes.input_format) { case INPUT_UC8: bytes_per_sample = 2; break; case INPUT_SC16: case INPUT_SC16Q11: bytes_per_sample = 4; break; } if (!(readbuf = malloc(MODES_MAG_BUF_SAMPLES * bytes_per_sample))) { fprintf(stderr, "failed to allocate read buffer\n"); exit(1); } clock_gettime(CLOCK_MONOTONIC, &next_buffer_delivery); pthread_mutex_lock(&Modes.data_mutex); while (!Modes.exit && !eof) { ssize_t nread, toread; void *r; struct mag_buf *outbuf, *lastbuf; unsigned next_free_buffer; unsigned slen; next_free_buffer = (Modes.first_free_buffer + 1) % MODES_MAG_BUFFERS; if (next_free_buffer == Modes.first_filled_buffer) { // no space for output yet pthread_cond_wait(&Modes.data_cond, &Modes.data_mutex); continue; } outbuf = &Modes.mag_buffers[Modes.first_free_buffer]; lastbuf = &Modes.mag_buffers[(Modes.first_free_buffer + MODES_MAG_BUFFERS - 1) % MODES_MAG_BUFFERS]; pthread_mutex_unlock(&Modes.data_mutex); // Compute the sample timestamp and system timestamp for the start of the block outbuf->sampleTimestamp = lastbuf->sampleTimestamp + 12e6 * lastbuf->length / Modes.sample_rate; // Copy trailing data from last block (or reset if not valid) if (lastbuf->length >= Modes.trailing_samples) { memcpy(outbuf->data, lastbuf->data + lastbuf->length - Modes.trailing_samples, Modes.trailing_samples * sizeof(uint16_t)); } else { memset(outbuf->data, 0, Modes.trailing_samples * sizeof(uint16_t)); } // Get the system time for the start of this block clock_gettime(CLOCK_REALTIME, &outbuf->sysTimestamp); toread = MODES_MAG_BUF_SAMPLES * bytes_per_sample; r = readbuf; while (toread) { nread = read(Modes.fd, r, toread); if (nread <= 0) { // Done. eof = 1; break; } r += nread; toread -= nread; } slen = outbuf->length = MODES_MAG_BUF_SAMPLES - toread/bytes_per_sample; // Convert the new data convert_samples(readbuf, &outbuf->data[Modes.trailing_samples], slen, &outbuf->total_power); if (Modes.throttle) { // Wait until we are allowed to release this buffer to the main thread while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_buffer_delivery, NULL) == EINTR) ; // compute the time we can deliver the next buffer. next_buffer_delivery.tv_nsec += outbuf->length * 1e9 / Modes.sample_rate; normalize_timespec(&next_buffer_delivery); } // Push the new data to the main thread pthread_mutex_lock(&Modes.data_mutex); Modes.first_free_buffer = next_free_buffer; // accumulate CPU while holding the mutex, and restart measurement end_cpu_timing(&reader_thread_start, &Modes.reader_cpu_accumulator); start_cpu_timing(&reader_thread_start); pthread_cond_signal(&Modes.data_cond); } free(readbuf); // Wait for the main thread to consume all data while (!Modes.exit && Modes.first_filled_buffer != Modes.first_free_buffer) pthread_cond_wait(&Modes.data_cond, &Modes.data_mutex); pthread_mutex_unlock(&Modes.data_mutex); }
void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) { struct mag_buf *outbuf; struct mag_buf *lastbuf; uint32_t slen; unsigned next_free_buffer; unsigned free_bufs; unsigned block_duration; static int was_odd = 0; // paranoia!! static int dropping = 0; MODES_NOTUSED(ctx); // Lock the data buffer variables before accessing them pthread_mutex_lock(&Modes.data_mutex); if (Modes.exit) { rtlsdr_cancel_async(Modes.dev); // ask our caller to exit } next_free_buffer = (Modes.first_free_buffer + 1) % MODES_MAG_BUFFERS; outbuf = &Modes.mag_buffers[Modes.first_free_buffer]; lastbuf = &Modes.mag_buffers[(Modes.first_free_buffer + MODES_MAG_BUFFERS - 1) % MODES_MAG_BUFFERS]; free_bufs = (Modes.first_filled_buffer - next_free_buffer + MODES_MAG_BUFFERS) % MODES_MAG_BUFFERS; // Paranoia! Unlikely, but let's go for belt and suspenders here if (len != MODES_RTL_BUF_SIZE) { fprintf(stderr, "weirdness: rtlsdr gave us a block with an unusual size (got %u bytes, expected %u bytes)\n", (unsigned)len, (unsigned)MODES_RTL_BUF_SIZE); if (len > MODES_RTL_BUF_SIZE) { // wat?! Discard the start. unsigned discard = (len - MODES_RTL_BUF_SIZE + 1) / 2; outbuf->dropped += discard; buf += discard*2; len -= discard*2; } } if (was_odd) { // Drop a sample so we are in sync with I/Q samples again (hopefully) ++buf; --len; ++outbuf->dropped; } was_odd = (len & 1); slen = len/2; if (free_bufs == 0 || (dropping && free_bufs < MODES_MAG_BUFFERS/2)) { // FIFO is full. Drop this block. dropping = 1; outbuf->dropped += slen; pthread_mutex_unlock(&Modes.data_mutex); return; } dropping = 0; pthread_mutex_unlock(&Modes.data_mutex); // Compute the sample timestamp and system timestamp for the start of the block outbuf->sampleTimestamp = lastbuf->sampleTimestamp + 12e6 * (lastbuf->length + outbuf->dropped) / Modes.sample_rate; block_duration = 1e9 * slen / Modes.sample_rate; // Get the approx system time for the start of this block clock_gettime(CLOCK_REALTIME, &outbuf->sysTimestamp); outbuf->sysTimestamp.tv_nsec -= block_duration; normalize_timespec(&outbuf->sysTimestamp); // Copy trailing data from last block (or reset if not valid) if (outbuf->dropped == 0 && lastbuf->length >= Modes.trailing_samples) { memcpy(outbuf->data, lastbuf->data + lastbuf->length - Modes.trailing_samples, Modes.trailing_samples * sizeof(uint16_t)); } else { memset(outbuf->data, 0, Modes.trailing_samples * sizeof(uint16_t)); } // Convert the new data outbuf->length = slen; convert_samples(buf, &outbuf->data[Modes.trailing_samples], slen, &outbuf->total_power); // Push the new data to the demodulation thread pthread_mutex_lock(&Modes.data_mutex); Modes.mag_buffers[next_free_buffer].dropped = 0; Modes.mag_buffers[next_free_buffer].length = 0; // just in case Modes.first_free_buffer = next_free_buffer; // accumulate CPU while holding the mutex, and restart measurement end_cpu_timing(&reader_thread_start, &Modes.reader_cpu_accumulator); start_cpu_timing(&reader_thread_start); pthread_cond_signal(&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); }