@@ -234,6 +234,11 @@ typedef struct {
234234 uint8_t positions [VIRTIO_SND_CHMAP_MAX_SIZE ];
235235} virtio_snd_chmap_info_t ;
236236
237+ /* A queue to hold arbitrary number of PCM frames. */
238+ typedef struct {
239+ void * buf ;
240+ struct queue_head q ;
241+ } virtio_snd_pcm_frame_t ;
237242/* virtio-snd to hold the settings of each stream */
238243typedef struct {
239244 virtio_snd_jack_info_t j ;
@@ -244,7 +249,8 @@ typedef struct {
244249 bool is_guest_playing ;
245250
246251 // PCM frame buffer
247- void * buf ;
252+ virtio_snd_pcm_frame_t * pcm_frames ;
253+ struct queue_head pcm_frames_q ;
248254} virtio_snd_prop_t ;
249255
250256static virtio_snd_config_t vsnd_configs [VSND_DEV_CNT_MAX ];
@@ -434,8 +440,6 @@ static void virtio_snd_read_pcm_prepare(const virtio_snd_pcm_hdr_t *query,
434440 vsnd_props [stream_id ].audio_host =
435441 CNFAInit (NULL , "semu-virtio-snd" , virtio_snd_cb , 44100 , 0 , 1 , 0 ,
436442 vsnd_props [stream_id ].pp .buffer_bytes , NULL , NULL , & v );
437- size_t sz = vsnd_props [stream_id ].pp .buffer_bytes ;
438- vsnd_props [stream_id ].buf = malloc (sizeof (vsnd_props [stream_id ].buf ) * sz );
439443
440444 /* Control the callback to prepare the buffer */
441445 /* TODO: add lock to avoid race condition */
@@ -518,7 +522,6 @@ static void virtio_snd_read_pcm_release(const virtio_snd_pcm_hdr_t *query,
518522
519523 vsnd_props [stream_id ].pp .hdr .hdr .code = VIRTIO_SND_R_PCM_RELEASE ;
520524 CNFAClose (vsnd_props [stream_id ].audio_host );
521- free (vsnd_props [stream_id ].buf );
522525
523526 * plen = 0 ;
524527 fprintf (stderr , "virtio_snd_read_pcm_release\n" );
@@ -734,7 +737,10 @@ static int virtio_snd_tx_desc_handler(virtio_snd_state_t *vsnd,
734737#endif
735738 int idx = 0 ;
736739 uint32_t stream_id ;
737- uintptr_t base = vsnd -> ram ;
740+ uintptr_t base = (uintptr_t ) vsnd -> ram ;
741+ struct queue_head frame_q = vsnd_props [stream_id ].pcm_frames_q ;
742+ INIT_QUEUE_HEAD (& frame_q );
743+ virtio_snd_pcm_frame_t * frame = vsnd_props [stream_id ].pcm_frames ;
738744 queue_for_each_entry (node , & q , q )
739745 {
740746 uint32_t addr = node -> vq_desc .addr ;
@@ -746,6 +752,7 @@ static int virtio_snd_tx_desc_handler(virtio_snd_state_t *vsnd,
746752 (virtio_snd_pcm_xfer_t * ) (base + addr );
747753 stream_id = request -> stream_id ;
748754 fprintf (stderr , "stream_id %" PRIu32 "\n" , stream_id );
755+ goto early_continue ;
749756 } else if (idx == cnt - 1 ) { // the last descriptor
750757 virtio_snd_pcm_status_t * response =
751758 (virtio_snd_pcm_status_t * ) (base + addr );
@@ -755,12 +762,20 @@ static int virtio_snd_tx_desc_handler(virtio_snd_state_t *vsnd,
755762 * plen = sizeof (* response ); /* TODO: set the read length of buffer of
756763 PCM frames */
757764 fprintf (stderr , "TX response\n" );
765+ goto early_continue ;
758766 }
759767
768+ frame = (virtio_snd_pcm_frame_t * ) malloc (sizeof (* frame ));
769+ void * buf = (void * ) (base + addr );
770+ frame -> buf = (void * ) malloc (sizeof (frame -> buf ) * len );
771+ memcpy (frame -> buf , buf , len );
772+ queue_push (& frame -> q , & frame_q );
773+
774+ early_continue :
760775 idx ++ ;
761776 }
762777
763- /* Tear down the list and free space */
778+ /* Tear down the descriptor list and free space. */
764779 idx = 0 ;
765780 virtq_desc_queue_node_t * tmp = NULL ;
766781 queue_for_each_entry_safe (node , tmp , & q , q )
@@ -772,6 +787,19 @@ static int virtio_snd_tx_desc_handler(virtio_snd_state_t *vsnd,
772787 assert (idx == cnt );
773788 assert (queue_empty (& q ));
774789
790+ /* Tear down the PCM frames. (should use in pcm_release) */
791+ idx = 0 ;
792+ virtio_snd_pcm_frame_t * t = NULL ;
793+ queue_for_each_entry_safe (frame , t , & frame_q , q )
794+ {
795+ free (frame -> buf );
796+ queue_del (& frame -> q );
797+ free (frame );
798+ idx ++ ;
799+ }
800+ assert (idx == cnt - 2 );
801+ assert (queue_empty (& frame_q ));
802+
775803 return 0 ;
776804}
777805
0 commit comments