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:
Takashi Sakamoto 2019-06-12 17:44:16 +09:00 committed by Takashi Iwai
parent 521b2e11fa
commit 20358d4460
1 changed files with 49 additions and 53 deletions

View File

@ -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)) { if (err < 0) {
err = start_stream(oxfw, opposite); dev_err(&oxfw->unit->device,
"fail to start rx stream: %d\n", err);
goto error;
}
}
if (oxfw->has_output) {
if (!amdtp_stream_running(&oxfw->tx_stream)) {
err = start_stream(oxfw, &oxfw->tx_stream);
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 tx stream: %d\n", err);
goto end; 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);
}
} }
/* /*