1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * JACK Audio Connection Kit input device 3cabdff1aSopenharmony_ci * Copyright (c) 2009 Samalyse 4cabdff1aSopenharmony_ci * Author: Olivier Guilyardi <olivier samalyse com> 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * This file is part of FFmpeg. 7cabdff1aSopenharmony_ci * 8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 12cabdff1aSopenharmony_ci * 13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16cabdff1aSopenharmony_ci * Lesser General Public License for more details. 17cabdff1aSopenharmony_ci * 18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21cabdff1aSopenharmony_ci */ 22cabdff1aSopenharmony_ci 23cabdff1aSopenharmony_ci#include "config.h" 24cabdff1aSopenharmony_ci#include <semaphore.h> 25cabdff1aSopenharmony_ci#include <jack/jack.h> 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "libavutil/internal.h" 28cabdff1aSopenharmony_ci#include "libavutil/log.h" 29cabdff1aSopenharmony_ci#include "libavutil/fifo.h" 30cabdff1aSopenharmony_ci#include "libavutil/opt.h" 31cabdff1aSopenharmony_ci#include "libavutil/time.h" 32cabdff1aSopenharmony_ci#include "libavcodec/avcodec.h" 33cabdff1aSopenharmony_ci#include "libavformat/avformat.h" 34cabdff1aSopenharmony_ci#include "libavformat/internal.h" 35cabdff1aSopenharmony_ci#include "timefilter.h" 36cabdff1aSopenharmony_ci#include "avdevice.h" 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_ci/** 39cabdff1aSopenharmony_ci * Size of the internal FIFO buffers as a number of audio packets 40cabdff1aSopenharmony_ci */ 41cabdff1aSopenharmony_ci#define FIFO_PACKETS_NUM 16 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_citypedef struct JackData { 44cabdff1aSopenharmony_ci AVClass *class; 45cabdff1aSopenharmony_ci jack_client_t * client; 46cabdff1aSopenharmony_ci int activated; 47cabdff1aSopenharmony_ci sem_t packet_count; 48cabdff1aSopenharmony_ci jack_nframes_t sample_rate; 49cabdff1aSopenharmony_ci jack_nframes_t buffer_size; 50cabdff1aSopenharmony_ci jack_port_t ** ports; 51cabdff1aSopenharmony_ci int nports; 52cabdff1aSopenharmony_ci TimeFilter * timefilter; 53cabdff1aSopenharmony_ci AVFifo * new_pkts; 54cabdff1aSopenharmony_ci AVFifo * filled_pkts; 55cabdff1aSopenharmony_ci int pkt_xrun; 56cabdff1aSopenharmony_ci int jack_xrun; 57cabdff1aSopenharmony_ci} JackData; 58cabdff1aSopenharmony_ci 59cabdff1aSopenharmony_cistatic int process_callback(jack_nframes_t nframes, void *arg) 60cabdff1aSopenharmony_ci{ 61cabdff1aSopenharmony_ci /* Warning: this function runs in realtime. One mustn't allocate memory here 62cabdff1aSopenharmony_ci * or do any other thing that could block. */ 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_ci int i, j; 65cabdff1aSopenharmony_ci JackData *self = arg; 66cabdff1aSopenharmony_ci float * buffer; 67cabdff1aSopenharmony_ci jack_nframes_t latency, cycle_delay; 68cabdff1aSopenharmony_ci AVPacket pkt; 69cabdff1aSopenharmony_ci float *pkt_data; 70cabdff1aSopenharmony_ci double cycle_time; 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_ci if (!self->client) 73cabdff1aSopenharmony_ci return 0; 74cabdff1aSopenharmony_ci 75cabdff1aSopenharmony_ci /* The approximate delay since the hardware interrupt as a number of frames */ 76cabdff1aSopenharmony_ci cycle_delay = jack_frames_since_cycle_start(self->client); 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_ci /* Retrieve filtered cycle time */ 79cabdff1aSopenharmony_ci cycle_time = ff_timefilter_update(self->timefilter, 80cabdff1aSopenharmony_ci av_gettime() / 1000000.0 - (double) cycle_delay / self->sample_rate, 81cabdff1aSopenharmony_ci self->buffer_size); 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_ci /* Check if an empty packet is available, and if there's enough space to send it back once filled */ 84cabdff1aSopenharmony_ci if (!av_fifo_can_read(self->new_pkts) || 85cabdff1aSopenharmony_ci !av_fifo_can_write(self->filled_pkts)) { 86cabdff1aSopenharmony_ci self->pkt_xrun = 1; 87cabdff1aSopenharmony_ci return 0; 88cabdff1aSopenharmony_ci } 89cabdff1aSopenharmony_ci 90cabdff1aSopenharmony_ci /* Retrieve empty (but allocated) packet */ 91cabdff1aSopenharmony_ci av_fifo_read(self->new_pkts, &pkt, 1); 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci pkt_data = (float *) pkt.data; 94cabdff1aSopenharmony_ci latency = 0; 95cabdff1aSopenharmony_ci 96cabdff1aSopenharmony_ci /* Copy and interleave audio data from the JACK buffer into the packet */ 97cabdff1aSopenharmony_ci for (i = 0; i < self->nports; i++) { 98cabdff1aSopenharmony_ci jack_latency_range_t range; 99cabdff1aSopenharmony_ci jack_port_get_latency_range(self->ports[i], JackCaptureLatency, &range); 100cabdff1aSopenharmony_ci latency += range.max; 101cabdff1aSopenharmony_ci buffer = jack_port_get_buffer(self->ports[i], self->buffer_size); 102cabdff1aSopenharmony_ci for (j = 0; j < self->buffer_size; j++) 103cabdff1aSopenharmony_ci pkt_data[j * self->nports + i] = buffer[j]; 104cabdff1aSopenharmony_ci } 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci /* Timestamp the packet with the cycle start time minus the average latency */ 107cabdff1aSopenharmony_ci pkt.pts = (cycle_time - (double) latency / (self->nports * self->sample_rate)) * 1000000.0; 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci /* Send the now filled packet back, and increase packet counter */ 110cabdff1aSopenharmony_ci av_fifo_write(self->filled_pkts, &pkt, 1); 111cabdff1aSopenharmony_ci sem_post(&self->packet_count); 112cabdff1aSopenharmony_ci 113cabdff1aSopenharmony_ci return 0; 114cabdff1aSopenharmony_ci} 115cabdff1aSopenharmony_ci 116cabdff1aSopenharmony_cistatic void shutdown_callback(void *arg) 117cabdff1aSopenharmony_ci{ 118cabdff1aSopenharmony_ci JackData *self = arg; 119cabdff1aSopenharmony_ci self->client = NULL; 120cabdff1aSopenharmony_ci} 121cabdff1aSopenharmony_ci 122cabdff1aSopenharmony_cistatic int xrun_callback(void *arg) 123cabdff1aSopenharmony_ci{ 124cabdff1aSopenharmony_ci JackData *self = arg; 125cabdff1aSopenharmony_ci self->jack_xrun = 1; 126cabdff1aSopenharmony_ci ff_timefilter_reset(self->timefilter); 127cabdff1aSopenharmony_ci return 0; 128cabdff1aSopenharmony_ci} 129cabdff1aSopenharmony_ci 130cabdff1aSopenharmony_cistatic int supply_new_packets(JackData *self, AVFormatContext *context) 131cabdff1aSopenharmony_ci{ 132cabdff1aSopenharmony_ci AVPacket pkt; 133cabdff1aSopenharmony_ci int test, pkt_size = self->buffer_size * self->nports * sizeof(float); 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_ci /* Supply the process callback with new empty packets, by filling the new 136cabdff1aSopenharmony_ci * packets FIFO buffer with as many packets as possible. process_callback() 137cabdff1aSopenharmony_ci * can't do this by itself, because it can't allocate memory in realtime. */ 138cabdff1aSopenharmony_ci while (av_fifo_can_write(self->new_pkts)) { 139cabdff1aSopenharmony_ci if ((test = av_new_packet(&pkt, pkt_size)) < 0) { 140cabdff1aSopenharmony_ci av_log(context, AV_LOG_ERROR, "Could not create packet of size %d\n", pkt_size); 141cabdff1aSopenharmony_ci return test; 142cabdff1aSopenharmony_ci } 143cabdff1aSopenharmony_ci av_fifo_write(self->new_pkts, &pkt, 1); 144cabdff1aSopenharmony_ci } 145cabdff1aSopenharmony_ci return 0; 146cabdff1aSopenharmony_ci} 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_cistatic int start_jack(AVFormatContext *context) 149cabdff1aSopenharmony_ci{ 150cabdff1aSopenharmony_ci JackData *self = context->priv_data; 151cabdff1aSopenharmony_ci jack_status_t status; 152cabdff1aSopenharmony_ci int i, test; 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_ci /* Register as a JACK client, using the context url as client name. */ 155cabdff1aSopenharmony_ci self->client = jack_client_open(context->url, JackNullOption, &status); 156cabdff1aSopenharmony_ci if (!self->client) { 157cabdff1aSopenharmony_ci av_log(context, AV_LOG_ERROR, "Unable to register as a JACK client\n"); 158cabdff1aSopenharmony_ci return AVERROR(EIO); 159cabdff1aSopenharmony_ci } 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ci sem_init(&self->packet_count, 0, 0); 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci self->sample_rate = jack_get_sample_rate(self->client); 164cabdff1aSopenharmony_ci self->ports = av_malloc_array(self->nports, sizeof(*self->ports)); 165cabdff1aSopenharmony_ci if (!self->ports) 166cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 167cabdff1aSopenharmony_ci self->buffer_size = jack_get_buffer_size(self->client); 168cabdff1aSopenharmony_ci 169cabdff1aSopenharmony_ci /* Register JACK ports */ 170cabdff1aSopenharmony_ci for (i = 0; i < self->nports; i++) { 171cabdff1aSopenharmony_ci char str[32]; 172cabdff1aSopenharmony_ci snprintf(str, sizeof(str), "input_%d", i + 1); 173cabdff1aSopenharmony_ci self->ports[i] = jack_port_register(self->client, str, 174cabdff1aSopenharmony_ci JACK_DEFAULT_AUDIO_TYPE, 175cabdff1aSopenharmony_ci JackPortIsInput, 0); 176cabdff1aSopenharmony_ci if (!self->ports[i]) { 177cabdff1aSopenharmony_ci av_log(context, AV_LOG_ERROR, "Unable to register port %s:%s\n", 178cabdff1aSopenharmony_ci context->url, str); 179cabdff1aSopenharmony_ci jack_client_close(self->client); 180cabdff1aSopenharmony_ci return AVERROR(EIO); 181cabdff1aSopenharmony_ci } 182cabdff1aSopenharmony_ci } 183cabdff1aSopenharmony_ci 184cabdff1aSopenharmony_ci /* Register JACK callbacks */ 185cabdff1aSopenharmony_ci jack_set_process_callback(self->client, process_callback, self); 186cabdff1aSopenharmony_ci jack_on_shutdown(self->client, shutdown_callback, self); 187cabdff1aSopenharmony_ci jack_set_xrun_callback(self->client, xrun_callback, self); 188cabdff1aSopenharmony_ci 189cabdff1aSopenharmony_ci /* Create time filter */ 190cabdff1aSopenharmony_ci self->timefilter = ff_timefilter_new (1.0 / self->sample_rate, self->buffer_size, 1.5); 191cabdff1aSopenharmony_ci if (!self->timefilter) { 192cabdff1aSopenharmony_ci jack_client_close(self->client); 193cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 194cabdff1aSopenharmony_ci } 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_ci /* Create FIFO buffers */ 197cabdff1aSopenharmony_ci self->filled_pkts = av_fifo_alloc2(FIFO_PACKETS_NUM, sizeof(AVPacket), 0); 198cabdff1aSopenharmony_ci /* New packets FIFO with one extra packet for safety against underruns */ 199cabdff1aSopenharmony_ci self->new_pkts = av_fifo_alloc2((FIFO_PACKETS_NUM + 1), sizeof(AVPacket), 0); 200cabdff1aSopenharmony_ci if (!self->new_pkts) { 201cabdff1aSopenharmony_ci jack_client_close(self->client); 202cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 203cabdff1aSopenharmony_ci } 204cabdff1aSopenharmony_ci if ((test = supply_new_packets(self, context))) { 205cabdff1aSopenharmony_ci jack_client_close(self->client); 206cabdff1aSopenharmony_ci return test; 207cabdff1aSopenharmony_ci } 208cabdff1aSopenharmony_ci 209cabdff1aSopenharmony_ci return 0; 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_ci} 212cabdff1aSopenharmony_ci 213cabdff1aSopenharmony_cistatic void free_pkt_fifo(AVFifo **fifop) 214cabdff1aSopenharmony_ci{ 215cabdff1aSopenharmony_ci AVFifo *fifo = *fifop; 216cabdff1aSopenharmony_ci AVPacket pkt; 217cabdff1aSopenharmony_ci while (av_fifo_read(fifo, &pkt, 1) >= 0) 218cabdff1aSopenharmony_ci av_packet_unref(&pkt); 219cabdff1aSopenharmony_ci av_fifo_freep2(fifop); 220cabdff1aSopenharmony_ci} 221cabdff1aSopenharmony_ci 222cabdff1aSopenharmony_cistatic void stop_jack(JackData *self) 223cabdff1aSopenharmony_ci{ 224cabdff1aSopenharmony_ci if (self->client) { 225cabdff1aSopenharmony_ci if (self->activated) 226cabdff1aSopenharmony_ci jack_deactivate(self->client); 227cabdff1aSopenharmony_ci jack_client_close(self->client); 228cabdff1aSopenharmony_ci } 229cabdff1aSopenharmony_ci sem_destroy(&self->packet_count); 230cabdff1aSopenharmony_ci free_pkt_fifo(&self->new_pkts); 231cabdff1aSopenharmony_ci free_pkt_fifo(&self->filled_pkts); 232cabdff1aSopenharmony_ci av_freep(&self->ports); 233cabdff1aSopenharmony_ci ff_timefilter_destroy(self->timefilter); 234cabdff1aSopenharmony_ci} 235cabdff1aSopenharmony_ci 236cabdff1aSopenharmony_cistatic int audio_read_header(AVFormatContext *context) 237cabdff1aSopenharmony_ci{ 238cabdff1aSopenharmony_ci JackData *self = context->priv_data; 239cabdff1aSopenharmony_ci AVStream *stream; 240cabdff1aSopenharmony_ci int test; 241cabdff1aSopenharmony_ci 242cabdff1aSopenharmony_ci if ((test = start_jack(context))) 243cabdff1aSopenharmony_ci return test; 244cabdff1aSopenharmony_ci 245cabdff1aSopenharmony_ci stream = avformat_new_stream(context, NULL); 246cabdff1aSopenharmony_ci if (!stream) { 247cabdff1aSopenharmony_ci stop_jack(self); 248cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 249cabdff1aSopenharmony_ci } 250cabdff1aSopenharmony_ci 251cabdff1aSopenharmony_ci stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 252cabdff1aSopenharmony_ci#if HAVE_BIGENDIAN 253cabdff1aSopenharmony_ci stream->codecpar->codec_id = AV_CODEC_ID_PCM_F32BE; 254cabdff1aSopenharmony_ci#else 255cabdff1aSopenharmony_ci stream->codecpar->codec_id = AV_CODEC_ID_PCM_F32LE; 256cabdff1aSopenharmony_ci#endif 257cabdff1aSopenharmony_ci stream->codecpar->sample_rate = self->sample_rate; 258cabdff1aSopenharmony_ci stream->codecpar->ch_layout.nb_channels = self->nports; 259cabdff1aSopenharmony_ci 260cabdff1aSopenharmony_ci avpriv_set_pts_info(stream, 64, 1, 1000000); /* 64 bits pts in us */ 261cabdff1aSopenharmony_ci return 0; 262cabdff1aSopenharmony_ci} 263cabdff1aSopenharmony_ci 264cabdff1aSopenharmony_cistatic int audio_read_packet(AVFormatContext *context, AVPacket *pkt) 265cabdff1aSopenharmony_ci{ 266cabdff1aSopenharmony_ci JackData *self = context->priv_data; 267cabdff1aSopenharmony_ci struct timespec timeout = {0, 0}; 268cabdff1aSopenharmony_ci int test; 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci /* Activate the JACK client on first packet read. Activating the JACK client 271cabdff1aSopenharmony_ci * means that process_callback() starts to get called at regular interval. 272cabdff1aSopenharmony_ci * If we activate it in audio_read_header(), we're actually reading audio data 273cabdff1aSopenharmony_ci * from the device before instructed to, and that may result in an overrun. */ 274cabdff1aSopenharmony_ci if (!self->activated) { 275cabdff1aSopenharmony_ci if (!jack_activate(self->client)) { 276cabdff1aSopenharmony_ci self->activated = 1; 277cabdff1aSopenharmony_ci av_log(context, AV_LOG_INFO, 278cabdff1aSopenharmony_ci "JACK client registered and activated (rate=%dHz, buffer_size=%d frames)\n", 279cabdff1aSopenharmony_ci self->sample_rate, self->buffer_size); 280cabdff1aSopenharmony_ci } else { 281cabdff1aSopenharmony_ci av_log(context, AV_LOG_ERROR, "Unable to activate JACK client\n"); 282cabdff1aSopenharmony_ci return AVERROR(EIO); 283cabdff1aSopenharmony_ci } 284cabdff1aSopenharmony_ci } 285cabdff1aSopenharmony_ci 286cabdff1aSopenharmony_ci /* Wait for a packet coming back from process_callback(), if one isn't available yet */ 287cabdff1aSopenharmony_ci timeout.tv_sec = av_gettime() / 1000000 + 2; 288cabdff1aSopenharmony_ci if (sem_timedwait(&self->packet_count, &timeout)) { 289cabdff1aSopenharmony_ci if (errno == ETIMEDOUT) { 290cabdff1aSopenharmony_ci av_log(context, AV_LOG_ERROR, 291cabdff1aSopenharmony_ci "Input error: timed out when waiting for JACK process callback output\n"); 292cabdff1aSopenharmony_ci } else { 293cabdff1aSopenharmony_ci char errbuf[128]; 294cabdff1aSopenharmony_ci int ret = AVERROR(errno); 295cabdff1aSopenharmony_ci av_strerror(ret, errbuf, sizeof(errbuf)); 296cabdff1aSopenharmony_ci av_log(context, AV_LOG_ERROR, "Error while waiting for audio packet: %s\n", 297cabdff1aSopenharmony_ci errbuf); 298cabdff1aSopenharmony_ci } 299cabdff1aSopenharmony_ci if (!self->client) 300cabdff1aSopenharmony_ci av_log(context, AV_LOG_ERROR, "Input error: JACK server is gone\n"); 301cabdff1aSopenharmony_ci 302cabdff1aSopenharmony_ci return AVERROR(EIO); 303cabdff1aSopenharmony_ci } 304cabdff1aSopenharmony_ci 305cabdff1aSopenharmony_ci if (self->pkt_xrun) { 306cabdff1aSopenharmony_ci av_log(context, AV_LOG_WARNING, "Audio packet xrun\n"); 307cabdff1aSopenharmony_ci self->pkt_xrun = 0; 308cabdff1aSopenharmony_ci } 309cabdff1aSopenharmony_ci 310cabdff1aSopenharmony_ci if (self->jack_xrun) { 311cabdff1aSopenharmony_ci av_log(context, AV_LOG_WARNING, "JACK xrun\n"); 312cabdff1aSopenharmony_ci self->jack_xrun = 0; 313cabdff1aSopenharmony_ci } 314cabdff1aSopenharmony_ci 315cabdff1aSopenharmony_ci /* Retrieve the packet filled with audio data by process_callback() */ 316cabdff1aSopenharmony_ci av_fifo_read(self->filled_pkts, pkt, 1); 317cabdff1aSopenharmony_ci 318cabdff1aSopenharmony_ci if ((test = supply_new_packets(self, context))) 319cabdff1aSopenharmony_ci return test; 320cabdff1aSopenharmony_ci 321cabdff1aSopenharmony_ci return 0; 322cabdff1aSopenharmony_ci} 323cabdff1aSopenharmony_ci 324cabdff1aSopenharmony_cistatic int audio_read_close(AVFormatContext *context) 325cabdff1aSopenharmony_ci{ 326cabdff1aSopenharmony_ci JackData *self = context->priv_data; 327cabdff1aSopenharmony_ci stop_jack(self); 328cabdff1aSopenharmony_ci return 0; 329cabdff1aSopenharmony_ci} 330cabdff1aSopenharmony_ci 331cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(JackData, x) 332cabdff1aSopenharmony_cistatic const AVOption options[] = { 333cabdff1aSopenharmony_ci { "channels", "Number of audio channels.", OFFSET(nports), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, 334cabdff1aSopenharmony_ci { NULL }, 335cabdff1aSopenharmony_ci}; 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_cistatic const AVClass jack_indev_class = { 338cabdff1aSopenharmony_ci .class_name = "JACK indev", 339cabdff1aSopenharmony_ci .item_name = av_default_item_name, 340cabdff1aSopenharmony_ci .option = options, 341cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 342cabdff1aSopenharmony_ci .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, 343cabdff1aSopenharmony_ci}; 344cabdff1aSopenharmony_ci 345cabdff1aSopenharmony_ciconst AVInputFormat ff_jack_demuxer = { 346cabdff1aSopenharmony_ci .name = "jack", 347cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("JACK Audio Connection Kit"), 348cabdff1aSopenharmony_ci .priv_data_size = sizeof(JackData), 349cabdff1aSopenharmony_ci .read_header = audio_read_header, 350cabdff1aSopenharmony_ci .read_packet = audio_read_packet, 351cabdff1aSopenharmony_ci .read_close = audio_read_close, 352cabdff1aSopenharmony_ci .flags = AVFMT_NOFILE, 353cabdff1aSopenharmony_ci .priv_class = &jack_indev_class, 354cabdff1aSopenharmony_ci}; 355