static int init(struct ao *ao) { struct priv *priv = ao->priv; ao->untimed = priv->untimed; struct mp_chmap_sel sel = {.tmp = ao}; if (priv->channel_layouts) { for (int n = 0; priv->channel_layouts[n]; n++) { struct mp_chmap map = {0}; if (!mp_chmap_from_str(&map, bstr0(priv->channel_layouts[n]))) { MP_FATAL(ao, "Invalid channel map in option.\n"); return -1; } mp_chmap_sel_add_map(&sel, &map); } } else { mp_chmap_sel_add_any(&sel); } if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) mp_chmap_from_channels(&ao->channels, 2); priv->latency = priv->latency_sec * ao->samplerate; // A "buffer" for this many seconds of audio int bursts = (int)(ao->samplerate * priv->bufferlen + 1) / priv->outburst; priv->buffersize = priv->outburst * bursts + priv->latency; priv->last_time = mp_time_sec(); return 0; }
static int init(struct ao *ao) { struct priv *priv = ao->priv; ao->untimed = priv->untimed; struct mp_chmap_sel sel = {.tmp = ao}; if (priv->channel_layouts.num_chmaps) { for (int n = 0; n < priv->channel_layouts.num_chmaps; n++) mp_chmap_sel_add_map(&sel, &priv->channel_layouts.chmaps[n]); } else { mp_chmap_sel_add_any(&sel); } if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) mp_chmap_from_channels(&ao->channels, 2); priv->latency = priv->latency_sec * ao->samplerate; // A "buffer" for this many seconds of audio int bursts = (int)(ao->samplerate * priv->bufferlen + 1) / priv->outburst; priv->buffersize = priv->outburst * bursts + priv->latency; priv->last_time = mp_time_sec(); return 0; }
bool ca_init_chmap(struct ao *ao, AudioDeviceID device) { void *ta_ctx = talloc_new(NULL); struct mp_chmap_sel chmap_sel = {.tmp = ta_ctx}; struct mp_chmap chmap = {0}; AudioChannelLayout *ml = ca_query_layout(ao, device, ta_ctx); if (ml && ca_layout_to_mp_chmap(ao, ml, &chmap)) mp_chmap_sel_add_map(&chmap_sel, &chmap); AudioChannelLayout *sl = ca_query_stereo_layout(ao, device, ta_ctx); if (sl && ca_layout_to_mp_chmap(ao, sl, &chmap)) mp_chmap_sel_add_map(&chmap_sel, &chmap); if (!ao_chmap_sel_adjust(ao, &chmap_sel, &ao->channels)) { MP_ERR(ao, "could not select a suitable channel map among the " "hardware supported ones. Make sure to configure your " "output device correctly in 'Audio MIDI Setup.app'\n"); goto coreaudio_error; } talloc_free(ta_ctx); return true; coreaudio_error: talloc_free(ta_ctx); return false; }
static int init(struct ao *ao) { float position[3] = {0, 0, 0}; float direction[6] = {0, 0, 1, 0, -1, 0}; ALCdevice *dev = NULL; ALCcontext *ctx = NULL; ALCint freq = 0; ALCint attribs[] = {ALC_FREQUENCY, ao->samplerate, 0, 0}; int i; struct priv *p = ao->priv; if (ao_data) { MP_FATAL(ao, "Not reentrant!\n"); return -1; } ao_data = ao; ao->no_persistent_volume = true; struct mp_chmap_sel sel = {0}; for (i = 0; speaker_pos[i].id != -1; i++) mp_chmap_sel_add_speaker(&sel, speaker_pos[i].id); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto err_out; struct speaker speakers[MAX_CHANS]; for (i = 0; i < ao->channels.num; i++) { speakers[i].id = -1; for (int n = 0; speaker_pos[n].id >= 0; n++) { if (speaker_pos[n].id == ao->channels.speaker[i]) speakers[i] = speaker_pos[n]; } if (speakers[i].id < 0) { MP_FATAL(ao, "Unknown channel layout\n"); goto err_out; } } dev = alcOpenDevice(p->cfg_device && p->cfg_device[0] ? p->cfg_device : NULL); if (!dev) { MP_FATAL(ao, "could not open device\n"); goto err_out; } ctx = alcCreateContext(dev, attribs); alcMakeContextCurrent(ctx); alListenerfv(AL_POSITION, position); alListenerfv(AL_ORIENTATION, direction); alGenSources(ao->channels.num, sources); for (i = 0; i < ao->channels.num; i++) { cur_buf[i] = 0; unqueue_buf[i] = 0; alGenBuffers(NUM_BUF, buffers[i]); alSourcefv(sources[i], AL_POSITION, speakers[i].pos); alSource3f(sources[i], AL_VELOCITY, 0, 0, 0); } alcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq); if (alcGetError(dev) == ALC_NO_ERROR && freq) ao->samplerate = freq; ao->format = AF_FORMAT_S16_NE; tmpbuf = malloc(CHUNK_SIZE); return 0; err_out: return -1; }
static bool select_chmap(struct ao *ao, pa_channel_map *dst) { struct mp_chmap_sel sel = {0}; for (int n = 0; speaker_map[n][1] != -1; n++) mp_chmap_sel_add_speaker(&sel, speaker_map[n][1]); return ao_chmap_sel_adjust(ao, &sel, &ao->channels) && chmap_pa_from_mp(dst, &ao->channels); }
static int init(struct ao *ao) { MP_VERBOSE(ao, "init!\n"); ao->format = af_fmt_from_planar(ao->format); struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) return -1; struct wasapi_state *state = (struct wasapi_state *)ao->priv; state->log = ao->log; wasapi_fill_VistaBlob(state); if (state->opt_list) { wasapi_enumerate_devices(state->log, NULL, NULL); } if (state->opt_exclusive) { state->share_mode = AUDCLNT_SHAREMODE_EXCLUSIVE; } else { state->share_mode = AUDCLNT_SHAREMODE_SHARED; } state->init_done = CreateEventW(NULL, FALSE, FALSE, NULL); state->hUninit = CreateEventW(NULL, FALSE, FALSE, NULL); state->hFeed = CreateEventW(NULL, FALSE, FALSE, NULL); /* for wasapi event mode */ state->hForceFeed = CreateEventW(NULL, FALSE, FALSE, NULL); state->hFeedDone = CreateEventW(NULL, FALSE, FALSE, NULL); if (!state->init_done || !state->hFeed || !state->hUninit || !state->hForceFeed || !state->hFeedDone) { closehandles(ao); /* failed to init events */ return -1; } state->init_ret = -1; state->threadLoop = (HANDLE)CreateThread(NULL, 0, &ThreadLoop, ao, 0, NULL); if (!state->threadLoop) { /* failed to init thread */ MP_ERR(ao, "fail to create thread!\n"); return -1; } WaitForSingleObject(state->init_done, INFINITE); /* wait on init complete */ if (state->init_ret) { if (!ao->probing) { MP_ERR(ao, "thread_init failed!\n"); } } else MP_VERBOSE(ao, "Init Done!\n"); wasapi_setup_proxies(state); return state->init_ret; }
static int init(struct ao *ao) { struct priv *priv = ao->priv; if (rsd_init(&priv->rd) < 0) return -1; // Actual channel layout unknown. struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext_def(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) { rsd_free(priv->rd); return -1; } rsd_set_param(priv->rd, RSD_SAMPLERATE, (int[]) { ao->samplerate });
bool ca_init_chmap(struct ao *ao, AudioDeviceID device) { struct mp_chmap_sel chmap_sel = {0}; ca_retrieve_layouts(ao, &chmap_sel, device); if (!chmap_sel.num_chmaps) mp_chmap_sel_add_map(&chmap_sel, &(struct mp_chmap)MP_CHMAP_INIT_STEREO); mp_chmap_sel_add_map(&chmap_sel, &(struct mp_chmap)MP_CHMAP_INIT_MONO); if (!ao_chmap_sel_adjust(ao, &chmap_sel, &ao->channels)) { MP_ERR(ao, "could not select a suitable channel map among the " "hardware supported ones. Make sure to configure your " "output device correctly in 'Audio MIDI Setup.app'\n"); return false; } return true; }
static int init(struct ao *ao) { struct priv *priv = ao->priv; ao->untimed = priv->untimed; struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_any(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) mp_chmap_from_channels(&ao->channels, 2); priv->latency = priv->latency_sec * ao->samplerate; // A "buffer" for this many seconds of audio int bursts = (int)(ao->samplerate * priv->bufferlen + 1) / priv->outburst; priv->buffersize = priv->outburst * bursts + priv->latency; priv->last_time = mp_time_sec(); return 0; }
static int init(struct ao *ao) { struct priv *priv = ao->priv; if (rsd_init(&priv->rd) < 0) return -1; if (priv->host && priv->host[0]) rsd_set_param(priv->rd, RSD_HOST, priv->host); if (priv->port && priv->port[0]) rsd_set_param(priv->rd, RSD_PORT, priv->port); // Actual channel layout unknown. struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext_def(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) { rsd_free(priv->rd); return -1; } rsd_set_param(priv->rd, RSD_SAMPLERATE, &ao->samplerate); rsd_set_param(priv->rd, RSD_CHANNELS, &ao->channels.num); ao->format = af_fmt_from_planar(ao->format); int rsd_format = set_format(ao); rsd_set_param(priv->rd, RSD_FORMAT, &rsd_format); if (rsd_start(priv->rd) < 0) { rsd_free(priv->rd); return -1; } return 0; }
static int init(struct ao *ao) { struct priv *p = ao->priv; const char **matching_ports = NULL; char *port_name = p->cfg_port && p->cfg_port[0] ? p->cfg_port : NULL; jack_options_t open_options = JackNullOption; int port_flags = JackPortIsInput; int i; struct mp_chmap_sel sel = {0}; if (p->stdlayout == 0) { mp_chmap_sel_add_waveext(&sel); } else if (p->stdlayout == 1) { mp_chmap_sel_add_alsa_def(&sel); } else { mp_chmap_sel_add_any(&sel); } if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto err_out; if (!p->autostart) open_options |= JackNoStartServer; p->client = jack_client_open(p->cfg_client_name, open_options, NULL); if (!p->client) { MP_FATAL(ao, "cannot open server\n"); goto err_out; } jack_set_process_callback(p->client, outputaudio, ao); // list matching ports if connections should be made if (p->connect) { if (!port_name) port_flags |= JackPortIsPhysical; matching_ports = jack_get_ports(p->client, port_name, NULL, port_flags); if (!matching_ports || !matching_ports[0]) { MP_FATAL(ao, "no physical ports available\n"); goto err_out; } i = 1; p->num_ports = ao->channels.num; while (matching_ports[i]) i++; if (p->num_ports > i) p->num_ports = i; } // create out output ports for (i = 0; i < p->num_ports; i++) { char pname[30]; snprintf(pname, 30, "out_%d", i); p->ports[i] = jack_port_register(p->client, pname, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (!p->ports[i]) { MP_FATAL(ao, "not enough ports available\n"); goto err_out; } } if (jack_activate(p->client)) { MP_FATAL(ao, "activate failed\n"); goto err_out; } for (i = 0; i < p->num_ports; i++) { if (jack_connect(p->client, jack_port_name(p->ports[i]), matching_ports[i])) { MP_FATAL(ao, "connecting failed\n"); goto err_out; } } ao->samplerate = jack_get_sample_rate(p->client); jack_latency_range_t jack_latency_range; jack_port_get_latency_range(p->ports[0], JackPlaybackLatency, &jack_latency_range); p->jack_latency = (float)(jack_latency_range.max + jack_get_buffer_size(p->client)) / (float)ao->samplerate; p->callback_interval = 0; if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, p->num_ports)) goto err_out; ao->format = AF_FORMAT_FLOAT_NE; int unitsize = ao->channels.num * sizeof(float); p->outburst = (CHUNK_SIZE + unitsize - 1) / unitsize * unitsize; p->ring = mp_ring_new(p, NUM_CHUNKS * p->outburst); free(matching_ports); return 0; err_out: free(matching_ports); if (p->client) jack_client_close(p->client); return -1; }
static int init(struct ao *ao) { if (SDL_WasInit(SDL_INIT_AUDIO)) { mp_msg(MSGT_AO, MSGL_ERR, "[sdl] already initialized\n"); return -1; } struct priv *priv = ao->priv; if (SDL_InitSubSystem(SDL_INIT_AUDIO)) { if (!ao->probing) mp_msg(MSGT_AO, MSGL_ERR, "[sdl] SDL_Init failed\n"); uninit(ao, true); return -1; } struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext_def(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) { uninit(ao, true); return -1; } SDL_AudioSpec desired, obtained; switch (ao->format) { case AF_FORMAT_U8: desired.format = AUDIO_U8; break; case AF_FORMAT_S8: desired.format = AUDIO_S8; break; case AF_FORMAT_U16_LE: desired.format = AUDIO_U16LSB; break; case AF_FORMAT_U16_BE: desired.format = AUDIO_U16MSB; break; default: case AF_FORMAT_S16_LE: desired.format = AUDIO_S16LSB; break; case AF_FORMAT_S16_BE: desired.format = AUDIO_S16MSB; break; #ifdef AUDIO_S32LSB case AF_FORMAT_S32_LE: desired.format = AUDIO_S32LSB; break; #endif #ifdef AUDIO_S32MSB case AF_FORMAT_S32_BE: desired.format = AUDIO_S32MSB; break; #endif #ifdef AUDIO_F32LSB case AF_FORMAT_FLOAT_LE: desired.format = AUDIO_F32LSB; break; #endif #ifdef AUDIO_F32MSB case AF_FORMAT_FLOAT_BE: desired.format = AUDIO_F32MSB; break; #endif } desired.freq = ao->samplerate; desired.channels = ao->channels.num; desired.samples = FFMIN(32768, ceil_power_of_two(ao->samplerate * priv->buflen)); desired.callback = audio_callback; desired.userdata = ao; mp_msg(MSGT_AO, MSGL_V, "[sdl] requested format: %d Hz, %d channels, %x, " "buffer size: %d samples\n", (int) desired.freq, (int) desired.channels, (int) desired.format, (int) desired.samples); obtained = desired; if (SDL_OpenAudio(&desired, &obtained)) { if (!ao->probing) mp_msg(MSGT_AO, MSGL_ERR, "[sdl] could not open audio: %s\n", SDL_GetError()); uninit(ao, true); return -1; } mp_msg(MSGT_AO, MSGL_V, "[sdl] obtained format: %d Hz, %d channels, %x, " "buffer size: %d samples\n", (int) obtained.freq, (int) obtained.channels, (int) obtained.format, (int) obtained.samples); switch (obtained.format) { case AUDIO_U8: ao->format = AF_FORMAT_U8; break; case AUDIO_S8: ao->format = AF_FORMAT_S8; break; case AUDIO_S16LSB: ao->format = AF_FORMAT_S16_LE; break; case AUDIO_S16MSB: ao->format = AF_FORMAT_S16_BE; break; case AUDIO_U16LSB: ao->format = AF_FORMAT_U16_LE; break; case AUDIO_U16MSB: ao->format = AF_FORMAT_U16_BE; break; #ifdef AUDIO_S32LSB case AUDIO_S32LSB: ao->format = AF_FORMAT_S32_LE; break; #endif #ifdef AUDIO_S32MSB case AUDIO_S32MSB: ao->format = AF_FORMAT_S32_BE; break; #endif #ifdef AUDIO_F32LSB case AUDIO_F32LSB: ao->format = AF_FORMAT_FLOAT_LE; break; #endif #ifdef AUDIO_F32MSB case AUDIO_F32MSB: ao->format = AF_FORMAT_FLOAT_BE; break; #endif default: if (!ao->probing) mp_msg(MSGT_AO, MSGL_ERR, "[sdl] could not find matching format\n"); uninit(ao, true); return -1; } if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, obtained.channels)) { uninit(ao, true); return -1; } ao->samplerate = obtained.freq; priv->buffer = av_fifo_alloc(obtained.size * priv->bufcnt); priv->buffer_mutex = SDL_CreateMutex(); if (!priv->buffer_mutex) { mp_msg(MSGT_AO, MSGL_ERR, "[sdl] SDL_CreateMutex failed\n"); uninit(ao, true); return -1; } priv->underrun_cond = SDL_CreateCond(); if (!priv->underrun_cond) { mp_msg(MSGT_AO, MSGL_ERR, "[sdl] SDL_CreateCond failed\n"); uninit(ao, true); return -1; } priv->unpause = 1; priv->paused = 1; priv->callback_time0 = priv->callback_time1 = mp_time_us(); return 1; }
/** \brief setup sound device \param rate samplerate \param channels number of channels \param format format \param flags unused \return 0=success -1=fail */ static int init(struct ao *ao) { struct priv *p = ao->priv; int res; if (!InitDirectSound(ao)) return -1; ao->no_persistent_volume = true; p->audio_volume = 100; // ok, now create the buffers WAVEFORMATEXTENSIBLE wformat; DSBUFFERDESC dsbpridesc; DSBUFFERDESC dsbdesc; int format = af_fmt_from_planar(ao->format); int rate = ao->samplerate; if (AF_FORMAT_IS_AC3(format)) format = AF_FORMAT_AC3; else { struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) return -1; } switch (format) { case AF_FORMAT_AC3: case AF_FORMAT_S24_LE: case AF_FORMAT_S16_LE: case AF_FORMAT_U8: break; default: MP_VERBOSE(ao, "format %s not supported defaulting to Signed 16-bit Little-Endian\n", af_fmt_to_str(format)); format = AF_FORMAT_S16_LE; } //set our audio parameters ao->samplerate = rate; ao->format = format; ao->bps = ao->channels.num * rate * (af_fmt2bits(format) >> 3); int buffersize = ao->bps; // space for 1 sec MP_VERBOSE(ao, "Samplerate:%iHz Channels:%i Format:%s\n", rate, ao->channels.num, af_fmt_to_str(format)); MP_VERBOSE(ao, "Buffersize:%d bytes (%d msec)\n", buffersize, buffersize / ao->bps * 1000); //fill waveformatex ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE)); wformat.Format.cbSize = (ao->channels.num > 2) ? sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) : 0; wformat.Format.nChannels = ao->channels.num; wformat.Format.nSamplesPerSec = rate; if (AF_FORMAT_IS_AC3(format)) { wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; wformat.Format.wBitsPerSample = 16; wformat.Format.nBlockAlign = 4; } else { wformat.Format.wFormatTag = (ao->channels.num > 2) ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM; wformat.Format.wBitsPerSample = af_fmt2bits(format); wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3); } // fill in primary sound buffer descriptor memset(&dsbpridesc, 0, sizeof(DSBUFFERDESC)); dsbpridesc.dwSize = sizeof(DSBUFFERDESC); dsbpridesc.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbpridesc.dwBufferBytes = 0; dsbpridesc.lpwfxFormat = NULL; // fill in the secondary sound buffer (=stream buffer) descriptor memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); dsbdesc.dwSize = sizeof(DSBUFFERDESC); dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /** Better position accuracy */ | DSBCAPS_GLOBALFOCUS /** Allows background playing */ | DSBCAPS_CTRLVOLUME; /** volume control enabled */ if (ao->channels.num > 2) { wformat.dwChannelMask = mp_chmap_to_waveext(&ao->channels); wformat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; wformat.Samples.wValidBitsPerSample = wformat.Format.wBitsPerSample; // Needed for 5.1 on emu101k - shit soundblaster dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE; } wformat.Format.nAvgBytesPerSec = wformat.Format.nSamplesPerSec * wformat.Format.nBlockAlign; dsbdesc.dwBufferBytes = buffersize; dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wformat; p->buffer_size = dsbdesc.dwBufferBytes; p->write_offset = 0; p->min_free_space = wformat.Format.nBlockAlign; p->outburst = wformat.Format.nBlockAlign * 512; // create primary buffer and set its format res = IDirectSound_CreateSoundBuffer(p->hds, &dsbpridesc, &p->hdspribuf, NULL); if (res != DS_OK) { UninitDirectSound(ao); MP_ERR(ao, "cannot create primary buffer (%s)\n", dserr2str(res)); return -1; } res = IDirectSoundBuffer_SetFormat(p->hdspribuf, (WAVEFORMATEX *)&wformat); if (res != DS_OK) { MP_WARN(ao, "cannot set primary buffer format (%s), using " "standard setting (bad quality)", dserr2str(res)); } MP_VERBOSE(ao, "primary buffer created\n"); // now create the stream buffer res = IDirectSound_CreateSoundBuffer(p->hds, &dsbdesc, &p->hdsbuf, NULL); if (res != DS_OK) { if (dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE) { // Try without DSBCAPS_LOCHARDWARE dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE; res = IDirectSound_CreateSoundBuffer(p->hds, &dsbdesc, &p->hdsbuf, NULL); } if (res != DS_OK) { UninitDirectSound(ao); MP_ERR(ao, "cannot create secondary (stream)buffer (%s)\n", dserr2str(res)); return -1; } } MP_VERBOSE(ao, "secondary (stream)buffer created\n"); return 0; }
/* * open device and setup parameters * return: 0=success -1=fail */ static int init(struct ao *ao) { struct priv *p = ao->priv; struct af_to_par { int format, bits, sig, le; } static const af_to_par[] = { {AF_FORMAT_U8, 8, 0, 0}, {AF_FORMAT_S8, 8, 1, 0}, {AF_FORMAT_U16_LE, 16, 0, 1}, {AF_FORMAT_U16_BE, 16, 0, 0}, {AF_FORMAT_S16_LE, 16, 1, 1}, {AF_FORMAT_S16_BE, 16, 1, 0}, {AF_FORMAT_U24_LE, 16, 0, 1}, {AF_FORMAT_U24_BE, 24, 0, 0}, {AF_FORMAT_S24_LE, 24, 1, 1}, {AF_FORMAT_S24_BE, 24, 1, 0}, {AF_FORMAT_U32_LE, 32, 0, 1}, {AF_FORMAT_U32_BE, 32, 0, 0}, {AF_FORMAT_S32_LE, 32, 1, 1}, {AF_FORMAT_S32_BE, 32, 1, 0} }, *ap; int i; p->hdl = sio_open(p->dev, SIO_PLAY, 0); if (p->hdl == NULL) { MP_ERR(ao, "can't open sndio %s\n", p->dev); goto error; } ao->format = af_fmt_from_planar(ao->format); sio_initpar(&p->par); for (i = 0, ap = af_to_par;; i++, ap++) { if (i == sizeof(af_to_par) / sizeof(struct af_to_par)) { MP_VERBOSE(ao, "unsupported format\n"); p->par.bits = 16; p->par.sig = 1; p->par.le = SIO_LE_NATIVE; break; } if (ap->format == ao->format) { p->par.bits = ap->bits; p->par.sig = ap->sig; if (ap->bits > 8) p->par.le = ap->le; if (ap->bits != SIO_BPS(ap->bits)) p->par.bps = ap->bits / 8; break; } } p->par.rate = ao->samplerate; struct mp_chmap_sel sel = {0}; for (int n = 0; n < MP_NUM_CHANNELS+1; n++) mp_chmap_sel_add_map(&sel, &sndio_layouts[n]); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto error; p->par.pchan = ao->channels.num; p->par.appbufsz = p->par.rate * 250 / 1000; /* 250ms buffer */ p->par.round = p->par.rate * 10 / 1000; /* 10ms block size */ if (!sio_setpar(p->hdl, &p->par)) { MP_ERR(ao, "couldn't set params\n"); goto error; } if (!sio_getpar(p->hdl, &p->par)) { MP_ERR(ao, "couldn't get params\n"); goto error; } if (p->par.bits == 8 && p->par.bps == 1) { ao->format = p->par.sig ? AF_FORMAT_S8 : AF_FORMAT_U8; } else if (p->par.bits == 16 && p->par.bps == 2) { ao->format = p->par.sig ? (p->par.le ? AF_FORMAT_S16_LE : AF_FORMAT_S16_BE) : (p->par.le ? AF_FORMAT_U16_LE : AF_FORMAT_U16_BE); } else if ((p->par.bits == 24 || p->par.msb) && p->par.bps == 3) { ao->format = p->par.sig ? (p->par.le ? AF_FORMAT_S24_LE : AF_FORMAT_S24_BE) : (p->par.le ? AF_FORMAT_U24_LE : AF_FORMAT_U24_BE); } else if ((p->par.bits == 32 || p->par.msb) && p->par.bps == 4) { ao->format = p->par.sig ? (p->par.le ? AF_FORMAT_S32_LE : AF_FORMAT_S32_BE) : (p->par.le ? AF_FORMAT_U32_LE : AF_FORMAT_U32_BE); } else { MP_ERR(ao, "couldn't set format\n"); goto error; } ao->bps = p->par.bps * p->par.pchan * p->par.rate; p->havevol = sio_onvol(p->hdl, volcb, p); sio_onmove(p->hdl, movecb, p); p->delay = 0; if (!sio_start(p->hdl)) MP_ERR(ao, "init: couldn't start\n"); p->pfd = calloc (sio_nfds(p->hdl), sizeof (struct pollfd)); if (!p->pfd) goto error; return 0; error: if (p->hdl) sio_close(p->hdl); return -1; }
static int init(struct ao *ao) { if (SDL_WasInit(SDL_INIT_AUDIO)) { MP_ERR(ao, "already initialized\n"); return -1; } struct priv *priv = ao->priv; if (SDL_InitSubSystem(SDL_INIT_AUDIO)) { if (!ao->probing) MP_ERR(ao, "SDL_Init failed\n"); uninit(ao); return -1; } struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext_def(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) { uninit(ao); return -1; } ao->format = af_fmt_from_planar(ao->format); SDL_AudioSpec desired, obtained; desired.format = AUDIO_S16SYS; for (int n = 0; fmtmap[n][0]; n++) { if (ao->format == fmtmap[n][0]) { desired.format = fmtmap[n][1]; break; } } desired.freq = ao->samplerate; desired.channels = ao->channels.num; desired.samples = MPMIN(32768, ceil_power_of_two(ao->samplerate * priv->buflen)); desired.callback = audio_callback; desired.userdata = ao; MP_VERBOSE(ao, "requested format: %d Hz, %d channels, %x, " "buffer size: %d samples\n", (int) desired.freq, (int) desired.channels, (int) desired.format, (int) desired.samples); obtained = desired; if (SDL_OpenAudio(&desired, &obtained)) { if (!ao->probing) MP_ERR(ao, "could not open audio: %s\n", SDL_GetError()); uninit(ao); return -1; } MP_VERBOSE(ao, "obtained format: %d Hz, %d channels, %x, " "buffer size: %d samples\n", (int) obtained.freq, (int) obtained.channels, (int) obtained.format, (int) obtained.samples); // The sample count is usually the number of samples the callback requests, // which we assume is the period size. Normally, ao.c will allocate a large // enough buffer. But in case the period size should be pathologically // large, this will help. ao->device_buffer = 3 * obtained.samples; ao->format = 0; for (int n = 0; fmtmap[n][0]; n++) { if (obtained.format == fmtmap[n][1]) { ao->format = fmtmap[n][0]; break; } } if (!ao->format) { if (!ao->probing) MP_ERR(ao, "could not find matching format\n"); uninit(ao); return -1; } if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, obtained.channels)) { uninit(ao); return -1; } ao->samplerate = obtained.freq; priv->paused = 1; return 1; }
static int init(struct ao *ao) { float position[3] = {0, 0, 0}; float direction[6] = {0, 0, -1, 0, 1, 0}; ALCdevice *dev = NULL; ALCcontext *ctx = NULL; ALCint freq = 0; ALCint attribs[] = {ALC_FREQUENCY, ao->samplerate, 0, 0}; int i; struct priv *p = ao->priv; if (ao_data) { MP_FATAL(ao, "Not reentrant!\n"); return -1; } ao_data = ao; struct mp_chmap_sel sel = {0}; for (i = 0; speaker_pos[i].id != -1; i++) mp_chmap_sel_add_speaker(&sel, speaker_pos[i].id); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto err_out; struct speaker speakers[MAX_CHANS]; for (i = 0; i < ao->channels.num; i++) { speakers[i].id = -1; for (int n = 0; speaker_pos[n].id >= 0; n++) { if (speaker_pos[n].id == ao->channels.speaker[i]) speakers[i] = speaker_pos[n]; } if (speakers[i].id < 0) { MP_FATAL(ao, "Unknown channel layout\n"); goto err_out; } } char *dev_name = ao->device; dev = alcOpenDevice(dev_name && dev_name[0] ? dev_name : NULL); if (!dev) { MP_FATAL(ao, "could not open device\n"); goto err_out; } ctx = alcCreateContext(dev, attribs); alcMakeContextCurrent(ctx); alListenerfv(AL_POSITION, position); alListenerfv(AL_ORIENTATION, direction); alGenSources(ao->channels.num, sources); for (i = 0; i < ao->channels.num; i++) { cur_buf[i] = 0; unqueue_buf[i] = 0; alGenBuffers(NUM_BUF, buffers[i]); alSourcefv(sources[i], AL_POSITION, speakers[i].pos); alSource3f(sources[i], AL_VELOCITY, 0, 0, 0); } alcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq); if (alcGetError(dev) == ALC_NO_ERROR && freq) ao->samplerate = freq; p->al_format = AL_FALSE; int try_formats[AF_FORMAT_COUNT]; af_get_best_sample_formats(ao->format, try_formats); for (int n = 0; try_formats[n]; n++) { p->al_format = get_al_format(try_formats[n]); if (p->al_format != AL_FALSE) { ao->format = try_formats[n]; break; } } if (p->al_format == AL_FALSE) { MP_FATAL(ao, "Can't find appropriate sample format.\n"); uninit(ao); goto err_out; } p->chunk_size = CHUNK_SAMPLES * af_fmt_to_bytes(ao->format); return 0; err_out: ao_data = NULL; return -1; }
static int init(struct ao *ao) { struct priv *priv = ao->priv; if (!check_pa_ret(Pa_Initialize())) return -1; pthread_mutex_init(&priv->ring_mutex, NULL); int pa_device = Pa_GetDefaultOutputDevice(); if (priv->cfg_device && priv->cfg_device[0]) pa_device = find_device(priv->cfg_device); if (pa_device == paNoDevice) goto error_exit; // The actual channel order probably depends on the platform. struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext_def(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto error_exit; PaStreamParameters sp = { .device = pa_device, .channelCount = ao->channels.num, .suggestedLatency = Pa_GetDeviceInfo(pa_device)->defaultHighOutputLatency, }; ao->format = af_fmt_from_planar(ao->format); const struct format_map *fmt = format_maps; while (fmt->pa_format) { if (fmt->mp_format == ao->format) { PaStreamParameters test = sp; test.sampleFormat = fmt->pa_format; if (Pa_IsFormatSupported(NULL, &test, ao->samplerate) == paNoError) break; } fmt++; } if (!fmt->pa_format) { MP_VERBOSE(ao, "Unsupported format, using default.\n"); fmt = format_maps; } ao->format = fmt->mp_format; sp.sampleFormat = fmt->pa_format; priv->framelen = ao->channels.num * (af_fmt2bits(ao->format) / 8); ao->bps = ao->samplerate * priv->framelen; if (!check_pa_ret(Pa_IsFormatSupported(NULL, &sp, ao->samplerate))) goto error_exit; if (!check_pa_ret(Pa_OpenStream(&priv->stream, NULL, &sp, ao->samplerate, paFramesPerBufferUnspecified, paNoFlag, stream_callback, ao))) goto error_exit; priv->ring = mp_ring_new(priv, seconds_to_bytes(ao, 0.5)); return 0; error_exit: uninit(ao, true); return -1; } static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *priv = ao->priv; pthread_mutex_lock(&priv->ring_mutex); int write_len = mp_ring_write(priv->ring, data[0], samples * ao->sstride); if (flags & AOPLAY_FINAL_CHUNK) priv->play_remaining = true; pthread_mutex_unlock(&priv->ring_mutex); if (Pa_IsStreamStopped(priv->stream) == 1) check_pa_ret(Pa_StartStream(priv->stream)); return write_len / ao->sstride; } static int get_space(struct ao *ao) { struct priv *priv = ao->priv; pthread_mutex_lock(&priv->ring_mutex); int free = mp_ring_available(priv->ring); pthread_mutex_unlock(&priv->ring_mutex); return free / ao->sstride; } static float get_delay(struct ao *ao) { struct priv *priv = ao->priv; double stream_time = Pa_GetStreamTime(priv->stream); pthread_mutex_lock(&priv->ring_mutex); float frame_time = priv->play_time ? priv->play_time - stream_time : 0; float buffer_latency = (mp_ring_buffered(priv->ring) + priv->play_silence) / (float)ao->bps; pthread_mutex_unlock(&priv->ring_mutex); return buffer_latency + frame_time; } static void reset(struct ao *ao) { struct priv *priv = ao->priv; if (Pa_IsStreamStopped(priv->stream) != 1) check_pa_ret(Pa_AbortStream(priv->stream)); pthread_mutex_lock(&priv->ring_mutex); mp_ring_reset(priv->ring); priv->play_remaining = false; priv->play_time = 0; priv->play_silence = 0; pthread_mutex_unlock(&priv->ring_mutex); } static void pause(struct ao *ao) { struct priv *priv = ao->priv; check_pa_ret(Pa_AbortStream(priv->stream)); double stream_time = Pa_GetStreamTime(priv->stream); pthread_mutex_lock(&priv->ring_mutex); // When playback resumes, replace the lost audio (due to dropping the // portaudio/driver/hardware internal buffers) with silence. float frame_time = priv->play_time ? priv->play_time - stream_time : 0; priv->play_silence += seconds_to_bytes(ao, FFMAX(frame_time, 0)); priv->play_time = 0; pthread_mutex_unlock(&priv->ring_mutex); } static void resume(struct ao *ao) { struct priv *priv = ao->priv; check_pa_ret(Pa_StartStream(priv->stream)); } #define OPT_BASE_STRUCT struct priv const struct ao_driver audio_out_portaudio = { .description = "PortAudio", .name = "portaudio", .init = init, .uninit = uninit, .reset = reset, .get_space = get_space, .play = play, .get_delay = get_delay, .pause = pause, .resume = resume, .priv_size = sizeof(struct priv), .options = (const struct m_option[]) { OPT_STRING_VALIDATE("device", cfg_device, 0, validate_device_opt), {0} }, };
// open & setup audio device static int init(struct ao *ao) { struct priv *ac = talloc_zero(ao, struct priv); AVCodec *codec; ao->priv = ac; if (!encode_lavc_available(ao->encode_lavc_ctx)) { MP_ERR(ao, "the option --o (output file) must be specified\n"); return -1; } pthread_mutex_lock(&ao->encode_lavc_ctx->lock); if (encode_lavc_alloc_stream(ao->encode_lavc_ctx, AVMEDIA_TYPE_AUDIO, &ac->stream, &ac->codec) < 0) { MP_ERR(ao, "could not get a new audio stream\n"); goto fail; } codec = ao->encode_lavc_ctx->ac; int samplerate = af_select_best_samplerate(ao->samplerate, codec->supported_samplerates); if (samplerate > 0) ao->samplerate = samplerate; // TODO: Remove this redundancy with encode_lavc_alloc_stream also // setting the time base. // Using codec->time_bvase is deprecated, but needed for older lavf. ac->stream->time_base.num = 1; ac->stream->time_base.den = ao->samplerate; ac->codec->time_base.num = 1; ac->codec->time_base.den = ao->samplerate; ac->codec->sample_rate = ao->samplerate; struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_any(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto fail; mp_chmap_reorder_to_lavc(&ao->channels); ac->codec->channels = ao->channels.num; ac->codec->channel_layout = mp_chmap_to_lavc(&ao->channels); ac->codec->sample_fmt = AV_SAMPLE_FMT_NONE; select_format(ao, codec); ac->sample_size = af_fmt_to_bytes(ao->format); ac->codec->sample_fmt = af_to_avformat(ao->format); ac->codec->bits_per_raw_sample = ac->sample_size * 8; if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->codec) < 0) goto fail; ac->pcmhack = 0; if (ac->codec->frame_size <= 1) ac->pcmhack = av_get_bits_per_sample(ac->codec->codec_id) / 8; if (ac->pcmhack) ac->aframesize = 16384; // "enough" else ac->aframesize = ac->codec->frame_size; // enough frames for at least 0.25 seconds ac->framecount = ceil(ao->samplerate * 0.25 / ac->aframesize); // but at least one! ac->framecount = FFMAX(ac->framecount, 1); ac->savepts = AV_NOPTS_VALUE; ac->lastpts = AV_NOPTS_VALUE; ao->untimed = true; if (ao->channels.num > AV_NUM_DATA_POINTERS) goto fail; pthread_mutex_unlock(&ao->encode_lavc_ctx->lock); return 0; fail: pthread_mutex_unlock(&ao->encode_lavc_ctx->lock); ac->shutdown = true; return -1; }
// open & setup audio device static int init(struct ao *ao) { struct priv *ac = talloc_zero(ao, struct priv); AVCodec *codec; ao->priv = ac; if (!encode_lavc_available(ao->encode_lavc_ctx)) { MP_ERR(ao, "the option --o (output file) must be specified\n"); return -1; } pthread_mutex_lock(&ao->encode_lavc_ctx->lock); ac->stream = encode_lavc_alloc_stream(ao->encode_lavc_ctx, AVMEDIA_TYPE_AUDIO); if (!ac->stream) { MP_ERR(ao, "could not get a new audio stream\n"); goto fail; } codec = encode_lavc_get_codec(ao->encode_lavc_ctx, ac->stream); // ac->stream->time_base.num = 1; // ac->stream->time_base.den = ao->samplerate; // doing this breaks mpeg2ts in ffmpeg // which doesn't properly force the time base to be 90000 // furthermore, ffmpeg.c doesn't do this either and works ac->stream->codec->time_base.num = 1; ac->stream->codec->time_base.den = ao->samplerate; ac->stream->codec->sample_rate = ao->samplerate; struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_any(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto fail; mp_chmap_reorder_to_lavc(&ao->channels); ac->stream->codec->channels = ao->channels.num; ac->stream->codec->channel_layout = mp_chmap_to_lavc(&ao->channels); ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_NONE; select_format(ao, codec); ac->sample_size = af_fmt2bits(ao->format) / 8; ac->stream->codec->sample_fmt = af_to_avformat(ao->format); ac->stream->codec->bits_per_raw_sample = ac->sample_size * 8; if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->stream) < 0) goto fail; ac->pcmhack = 0; if (ac->stream->codec->frame_size <= 1) ac->pcmhack = av_get_bits_per_sample(ac->stream->codec->codec_id) / 8; if (ac->pcmhack) { ac->aframesize = 16384; // "enough" ac->buffer_size = ac->aframesize * ac->pcmhack * ao->channels.num * 2 + 200; } else { ac->aframesize = ac->stream->codec->frame_size; ac->buffer_size = ac->aframesize * ac->sample_size * ao->channels.num * 2 + 200; } if (ac->buffer_size < FF_MIN_BUFFER_SIZE) ac->buffer_size = FF_MIN_BUFFER_SIZE; ac->buffer = talloc_size(ac, ac->buffer_size); // enough frames for at least 0.25 seconds ac->framecount = ceil(ao->samplerate * 0.25 / ac->aframesize); // but at least one! ac->framecount = FFMAX(ac->framecount, 1); ac->savepts = MP_NOPTS_VALUE; ac->lastpts = MP_NOPTS_VALUE; ao->untimed = true; pthread_mutex_unlock(&ao->encode_lavc_ctx->lock); return 0; fail: pthread_mutex_unlock(&ao->encode_lavc_ctx->lock); return -1; }
static int init(int rate, const struct mp_chmap *channels, int format, int flags) { const char **matching_ports = NULL; char *port_name = NULL; char *client_name = NULL; int autostart = 0; int connect = 1; const opt_t subopts[] = { {"port", OPT_ARG_MSTRZ, &port_name, NULL}, {"name", OPT_ARG_MSTRZ, &client_name, NULL}, {"estimate", OPT_ARG_BOOL, &estimate, NULL}, {"autostart", OPT_ARG_BOOL, &autostart, NULL}, {"connect", OPT_ARG_BOOL, &connect, NULL}, {NULL} }; jack_options_t open_options = JackUseExactName; int port_flags = JackPortIsInput; int i; estimate = 1; if (subopt_parse(ao_subdevice, subopts) != 0) { print_help(); return 0; } struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext(&sel); if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels)) goto err_out; if (!client_name) { client_name = malloc(40); sprintf(client_name, "mpv [%d]", getpid()); } if (!autostart) open_options |= JackNoStartServer; client = jack_client_open(client_name, open_options, NULL); if (!client) { mp_msg(MSGT_AO, MSGL_FATAL, "[JACK] cannot open server\n"); goto err_out; } buffer = av_fifo_alloc(BUFFSIZE); jack_set_process_callback(client, outputaudio, 0); // list matching ports if connections should be made if (connect) { if (!port_name) port_flags |= JackPortIsPhysical; matching_ports = jack_get_ports(client, port_name, NULL, port_flags); if (!matching_ports || !matching_ports[0]) { mp_msg(MSGT_AO, MSGL_FATAL, "[JACK] no physical ports available\n"); goto err_out; } i = 1; num_ports = ao_data.channels.num; while (matching_ports[i]) i++; if (num_ports > i) num_ports = i; } // create out output ports for (i = 0; i < num_ports; i++) { char pname[30]; snprintf(pname, 30, "out_%d", i); ports[i] = jack_port_register(client, pname, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (!ports[i]) { mp_msg(MSGT_AO, MSGL_FATAL, "[JACK] not enough ports available\n"); goto err_out; } } if (jack_activate(client)) { mp_msg(MSGT_AO, MSGL_FATAL, "[JACK] activate failed\n"); goto err_out; } for (i = 0; i < num_ports; i++) { if (jack_connect(client, jack_port_name(ports[i]), matching_ports[i])) { mp_msg(MSGT_AO, MSGL_FATAL, "[JACK] connecting failed\n"); goto err_out; } } rate = jack_get_sample_rate(client); jack_latency_range_t jack_latency_range; jack_port_get_latency_range(ports[0], JackPlaybackLatency, &jack_latency_range); jack_latency = (float)(jack_latency_range.max + jack_get_buffer_size(client)) / (float)rate; callback_interval = 0; if (!ao_chmap_sel_get_def(&ao_data, &sel, &ao_data.channels, num_ports)) goto err_out; ao_data.samplerate = rate; ao_data.format = AF_FORMAT_FLOAT_NE; ao_data.bps = ao_data.channels.num * rate * sizeof(float); ao_data.buffersize = CHUNK_SIZE * NUM_CHUNKS; ao_data.outburst = CHUNK_SIZE; free(matching_ports); free(port_name); free(client_name); return 1; err_out: free(matching_ports); free(port_name); free(client_name); if (client) jack_client_close(client); av_fifo_free(buffer); buffer = NULL; return 0; }
static int init(struct ao *ao) { struct priv *p = ao->priv; struct mp_chmap_sel sel = {0}; jack_options_t open_options; ao->format = AF_FORMAT_FLOATP; switch (p->stdlayout) { case 0: mp_chmap_sel_add_waveext(&sel); break; case 1: mp_chmap_sel_add_alsa_def(&sel); break; default: mp_chmap_sel_add_any(&sel); } if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto err_chmap; open_options = JackNullOption; if (!p->autostart) open_options |= JackNoStartServer; p->client = jack_client_open(p->cfg_client_name, open_options, NULL); if (!p->client) { MP_FATAL(ao, "cannot open server\n"); goto err_client_open; } if (create_ports(ao, ao->channels.num)) goto err_create_ports; jack_set_process_callback(p->client, process, ao); if (jack_activate(p->client)) { MP_FATAL(ao, "activate failed\n"); goto err_activate; } ao->samplerate = jack_get_sample_rate(p->client); if (p->connect) if (connect_to_outports(ao)) goto err_connect; jack_latency_range_t jack_latency_range; jack_port_get_latency_range(p->ports[0], JackPlaybackLatency, &jack_latency_range); p->jack_latency = (float)(jack_latency_range.max + jack_get_buffer_size(p->client)) / (float)ao->samplerate; if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, p->num_ports)) goto err_chmap_sel_get_def; return 0; err_chmap_sel_get_def: err_connect: jack_deactivate(p->client); err_activate: err_create_ports: jack_client_close(p->client); err_client_open: err_chmap: return -1; }