ALSA: oxfw: start duplex streams if supported
It's inconvenient to handle two isochronous context separately each other. This commit unifies the counters to handle the two at the same time. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
521b2e11fa
commit
20358d4460
|
@ -254,96 +254,92 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
|
||||||
struct amdtp_stream *stream,
|
struct amdtp_stream *stream,
|
||||||
unsigned int rate, unsigned int pcm_channels)
|
unsigned int rate, unsigned int pcm_channels)
|
||||||
{
|
{
|
||||||
struct amdtp_stream *opposite;
|
|
||||||
struct snd_oxfw_stream_formation formation;
|
struct snd_oxfw_stream_formation formation;
|
||||||
enum avc_general_plug_dir dir;
|
enum avc_general_plug_dir dir;
|
||||||
unsigned int substreams, opposite_substreams;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (stream == &oxfw->tx_stream) {
|
if (oxfw->capture_substreams == 0 && oxfw->playback_substreams == 0)
|
||||||
substreams = oxfw->capture_substreams;
|
return -EIO;
|
||||||
opposite = &oxfw->rx_stream;
|
|
||||||
opposite_substreams = oxfw->playback_substreams;
|
|
||||||
dir = AVC_GENERAL_PLUG_DIR_OUT;
|
|
||||||
} else {
|
|
||||||
substreams = oxfw->playback_substreams;
|
|
||||||
opposite_substreams = oxfw->capture_substreams;
|
|
||||||
|
|
||||||
if (oxfw->has_output)
|
// Considering JACK/FFADO streaming:
|
||||||
opposite = &oxfw->rx_stream;
|
// TODO: This can be removed hwdep functionality becomes popular.
|
||||||
else
|
err = check_connection_used_by_others(oxfw, &oxfw->rx_stream);
|
||||||
opposite = NULL;
|
if (err < 0)
|
||||||
|
return err;
|
||||||
dir = AVC_GENERAL_PLUG_DIR_IN;
|
if (oxfw->has_output) {
|
||||||
|
err = check_connection_used_by_others(oxfw, &oxfw->tx_stream);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (substreams == 0)
|
if (stream == &oxfw->tx_stream)
|
||||||
goto end;
|
dir = AVC_GENERAL_PLUG_DIR_OUT;
|
||||||
|
else
|
||||||
/*
|
dir = AVC_GENERAL_PLUG_DIR_IN;
|
||||||
* Considering JACK/FFADO streaming:
|
|
||||||
* TODO: This can be removed hwdep functionality becomes popular.
|
|
||||||
*/
|
|
||||||
err = check_connection_used_by_others(oxfw, stream);
|
|
||||||
if (err < 0)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
|
err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto end;
|
return err;
|
||||||
if (rate == 0)
|
if (rate == 0)
|
||||||
rate = formation.rate;
|
rate = formation.rate;
|
||||||
if (pcm_channels == 0)
|
if (pcm_channels == 0)
|
||||||
pcm_channels = formation.pcm;
|
pcm_channels = formation.pcm;
|
||||||
|
|
||||||
if (formation.rate != rate || formation.pcm != pcm_channels ||
|
if (formation.rate != rate || formation.pcm != pcm_channels ||
|
||||||
amdtp_streaming_error(stream)) {
|
amdtp_streaming_error(&oxfw->rx_stream) ||
|
||||||
if (opposite != NULL) {
|
amdtp_streaming_error(&oxfw->tx_stream)) {
|
||||||
err = check_connection_used_by_others(oxfw, opposite);
|
stop_stream(oxfw, &oxfw->rx_stream);
|
||||||
if (err < 0)
|
if (oxfw->has_output)
|
||||||
goto end;
|
stop_stream(oxfw, &oxfw->tx_stream);
|
||||||
stop_stream(oxfw, opposite);
|
|
||||||
}
|
|
||||||
stop_stream(oxfw, stream);
|
|
||||||
|
|
||||||
err = set_stream_format(oxfw, stream, rate, pcm_channels);
|
err = set_stream_format(oxfw, stream, rate, pcm_channels);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(&oxfw->unit->device,
|
dev_err(&oxfw->unit->device,
|
||||||
"fail to set stream format: %d\n", err);
|
"fail to set stream format: %d\n", err);
|
||||||
goto end;
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start opposite stream if needed. */
|
if (!amdtp_stream_running(&oxfw->rx_stream)) {
|
||||||
if (opposite && !amdtp_stream_running(opposite) &&
|
err = start_stream(oxfw, &oxfw->rx_stream);
|
||||||
(opposite_substreams > 0)) {
|
|
||||||
err = start_stream(oxfw, opposite);
|
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(&oxfw->unit->device,
|
dev_err(&oxfw->unit->device,
|
||||||
"fail to restart stream: %d\n", err);
|
"fail to start rx stream: %d\n", err);
|
||||||
goto end;
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oxfw->has_output) {
|
||||||
|
if (!amdtp_stream_running(&oxfw->tx_stream)) {
|
||||||
|
err = start_stream(oxfw, &oxfw->tx_stream);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(&oxfw->unit->device,
|
||||||
|
"fail to start tx stream: %d\n", err);
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start requested stream. */
|
return 0;
|
||||||
if (!amdtp_stream_running(stream)) {
|
error:
|
||||||
err = start_stream(oxfw, stream);
|
stop_stream(oxfw, &oxfw->rx_stream);
|
||||||
if (err < 0)
|
cmp_connection_break(&oxfw->in_conn);
|
||||||
dev_err(&oxfw->unit->device,
|
if (oxfw->has_output) {
|
||||||
"fail to start stream: %d\n", err);
|
stop_stream(oxfw, &oxfw->tx_stream);
|
||||||
|
cmp_connection_break(&oxfw->out_conn);
|
||||||
}
|
}
|
||||||
end:
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
|
void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
|
||||||
struct amdtp_stream *stream)
|
struct amdtp_stream *stream)
|
||||||
{
|
{
|
||||||
if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) ||
|
if (oxfw->capture_substreams == 0 && oxfw->playback_substreams == 0) {
|
||||||
((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0)))
|
stop_stream(oxfw, &oxfw->rx_stream);
|
||||||
return;
|
|
||||||
|
|
||||||
stop_stream(oxfw, stream);
|
if (oxfw->has_output)
|
||||||
|
stop_stream(oxfw, &oxfw->tx_stream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue