0% found this document useful (0 votes)
34 views7 pages

ALSA Driver - HW Buffer - Dolinux - Blog Park

The document discusses the ALSA driver and its implementation of hardware (HW) buffers using a ring buffer structure to manage audio data transfer. It explains how the ALSA core moves data to the HW buffer and the role of various pointers in tracking read and write positions within the buffer. Additionally, it details the function snd_pcm_update_hw_ptr0, which updates the HW pointer during data writing and hardware interruptions.

Uploaded by

bhch1173
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
34 views7 pages

ALSA Driver - HW Buffer - Dolinux - Blog Park

The document discusses the ALSA driver and its implementation of hardware (HW) buffers using a ring buffer structure to manage audio data transfer. It explains how the ALSA core moves data to the HW buffer and the role of various pointers in tracking read and write positions within the buffer. Additionally, it details the function snd_pcm_update_hw_ptr0, which updates the HW pointer during data writing and hardware interruptions.

Uploaded by

bhch1173
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

12/29/24, 9:11 PM ALSA driver--HW Buffer - dolinux - Blog Park

dolinux
Linux kernel engineer, computer low-level technology enthusiast

front page manage Essays - 1613 articles - 713 comments - 283 views - 3.27 million

Free AI Assistant

https://www.cnblogs.com/pengdonglin137/articles/12772104.html 1/7
12/29/24, 9:11 PM ALSA driver--HW Buffer - dolinux - Blog Park

ALSA driver--HW Buffer

Reprinted: https://www.cnblogs.com/fellow1988/p/6204183.html

When the app calls snd_pcm_writei, the alsa core moves the data sent by the app to the HW
buffer (ie, DMA buffer), and the alsa driver reads the data from the HW buffer and transmits
it to the hardware for playback.

ALSA buffer is implemented using ring buffer, which consists of multiple HW buffers.

HW buffer is generally a DMA buffer of size buffer size allocated in the hw_params function
of the alsa driver.
Nickname: dolinux
Age: 12 years The reason why multiple HW buffers are used to form a ring buffer is to prevent the front
Followers: 343 and back positions of the read and write pointers from being frequently swapped (that is,
Following: 54
when the write pointer reaches the HW buffer boundary, it must return to the starting point
+Add Follow
of the HW buffer).

Ring buffer = n * HW buffer. Usually this n is relatively large, and the read and write pointers
search
are rarely swapped during the data reading and writing process.
Look for it
The following figure shows the implementation of ALSA buffer and the method of updating
Google Search
the read and write pointers.

Latest Essays

1. Submit a patch to AOSP

2. Compile the arm64 version of perfet


to

3. Executing protoc in the virtual machi


ne reports illegal instruction (Illegal instru
ction)

4.Timekeeping in the Linux Kernel

5. Preventing the reboot command fro


m being executed accidentally

hw_ptr_base is the starting position of the current HW buffer in the Ring buffer. When the
6. Kernel trouble - How to analyze com
read pointer reaches the end of the HW buffer, hw_ptr_base moves by the buffer size.
plex macro definitions?
hw_ptr is the read pointer of HW buffer. When alsa driver reads data from HW buffer and
7. Use the trace output format of functi sends it to sound card hardware, hw_ptr will move to the new position.
on graph
appl_ptr is the write pointer of HW buffer. When app calls snd_pcm_write to write data, alsa
8. The Linux kernel feature funcgraph-r core copies the data to HW buffer, and appl_ptr is updated.
etaddr I implemented has been merged i
nto Linux 6.13 Boundary is the Ring buffer boundary.

hw_ofs is the position of the read pointer in the current HW buffer, which is returned by
9. Source Insight imports Linux kernel s
pointer() of the alsa driver.
ource code

10.bpftrace man page


Free AI Assistant
appl_ofs is the position of the write pointer in the current HW buffer.

https://www.cnblogs.com/pengdonglin137/articles/12772104.html 2/7
12/29/24, 9:11 PM ALSA driver--HW Buffer - dolinux - Blog Park

The update of hw_ptr is done by calling snd_pcm_update_hw_ptr0. This function is called


when the app writes data, and is also called by snd_pcm_peroid_elapsed when the hardware
is interrupted.

1 static int snd_pcm_update_hw_ptr0( struct snd_pcm_substream * substream,


2 unsigned int in_interrupt)
3 {
4 struct snd_pcm_runtime *runtime = substream-> runtime;
5 snd_pcm_uframes_t pos;
6 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
7 snd_pcm_sframes_t hdelta, delta;
8 unsigned long jdelta;
9 unsigned long curr_jiffies;
10 struct timespec curr_tstamp;
11 struct timespec audio_tstamp;
12 int crossed_boundary = 0 ;
13
14 old_hw_ptr = runtime->status->hw_ptr; // Save the last hw_ptr, which will be
15
16 /*
17 * group pointer, time and jiffies reads to allow for more
18 * accurate correlations/corrections.
19 * The values ​
are stored at the end of this routine after
20 * corrections for hw_ptr position
21 */
22 pos = substream->ops->pointer(substream); // Get the offset of hw_ptr in the
23 curr_jiffies = jiffies;
24 if (runtime->tstamp_mode = = SNDRV_PCM_TSTAMP_ENABLE) { // Get the current t
25 if ((substream->ops->get_time_info) &&
26 (runtime->audio_tstamp_config.type_requested != SNDRV_PCM_AUDIO_TSTAMP_
27 substream->ops->get_time_info(substream, &curr_tstamp,&audio_tstam
28
29 /* re-test in case tstamp type is not supported in hardware and was
30 if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TST
31 snd_pcm_gettime(runtime, ( struct timespec *)& curr_tstamp);
32 } else
33 snd_pcm_gettime(runtime, ( struct timespec *)& curr_tstamp);
34 }
35
36 if (pos == SNDRV_PCM_POS_XRUN) {// XRUN occurs
37 xrun(substream);
38 return - EPIPE;
39 }
40 if (pos >= runtime->buffer_size) { // pos is greater than buffer size, excep
if (printk_ratelimit()) {
42 char name[ 16 ];
43 snd_pcm_debug_name(substream, name, sizeof (name));
44 pcm_err(substream->pcm, " invalid position: %s, pos = %ld, buffer size
45 runtime-> period_size);
46 }
47
​ pos = 0 ;
48 }

Free
49
50
AI Assistant
pos -= pos % runtime-> min_align;
trace_hwptr(substream, pos, in_interrupt);
51 hw_base = runtime->hw_ptr_base; // Current hw_base 52 new_hw_ptr = hw_ba

https://www.cnblogs.com/pengdonglin137/articles/12772104.html 3/7
12/29/24, 9:11 PM ALSA driver--HW Buffer - dolinux - Blog Park
57 if (delta > new_hw_ptr) { // If this time the interrupt position is added with pe
60 if (hdelta > runtime->hw_ptr_buffer_jiffies/ 2 + 1 ) { // The distance from the l
62 if (hw_base >= runtime-> boundary) {
63 hw_base = 0 ;
64 crossed_boundary++ ;
65 }
66 new_hw_ptr = hw_base + pos;
67 goto __delta;
68 }
69 }
70 }
71 / *

new_hw_ptr might be lower than old_hw_ptr in case when


72 /* pointer crosses the end of the ring buffer */
73 if (new_hw_ptr < old_hw_ptr) { // If the current hw_ptr is smaller than the p
74 hw_base += runtime-> buffer_size;
75 if (hw_base >= runtime->boundary) { // If hw_base > boundary, then hw_bas
76 hw_base = 0 ;
77 crossed_boundary++ ;
78 }
79 new_hw_ptr = hw_base + pos;
80 }
81 __delta:
82 delta = new_hw_ptr - old_hw_ptr;
83 if (delta < 0 ) // If the current hw_ptr is still smaller than the previous
84 delta += runtime-> boundary;
85
86 if (runtime->no_period_wakeup) { // If the hardware does not generate an inte
87
88 snd_pcm_sframes_t xrun_threshold;
89 /*
90 * Without regular period interrupts, we have to check
91 * the elapsed time to detect xruns.
92 */
93 jdelta = curr_jiffies - runtime-> hw_ptr_jiffies;
94 if (jdelta < runtime->hw_ptr_buffer_jiffies / 2 )
95 goto no_delta_check;
96 hdelta = jdelta - delta * HZ / runtime-> rate;
97 xrun_threshold = runtime->hw_ptr_buffer_jiffies / 2 + 1 ;
98 while (hdelta > xrun_threshold) {
99 delta += runtime-> buffer_size;
100 hw_base += runtime-> buffer_size;
101 if (hw_base >= runtime-> boundary) {
102 hw_base = 0 ;
103 crossed_boundary++ ;
104 }
105 new_hw_ptr = hw_base + pos;
106 hdelta -= runtime-> hw_ptr_buffer_jiffies;
107 }
Free AI
108 Assistant
goto no_delta_check;
109 }

https://www.cnblogs.com/pengdonglin137/articles/12772104.html 4/7
12/29/24, 9:11 PM ALSA driver--HW Buffer - dolinux - Blog Park
110
111 /* something must be really wrong */
112 if (delta >= runtime->buffer_size + runtime->period_size) { // If the curren
113 hw_ptr_error(substream, in_interrupt, " Unexpected hw_ptr " ,
114 " (stream=%i, pos=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n " ,
115 substream->stream, ( long )pos,
116 ( long ) new_hw_ptr, ( long )old_hw_ptr);
117 return
0 ; 118 }
119 120
/
* Do jiffies check
only in xrun_debug mode * /
121 if ( ! BATCH flag.
125 * Such hardware usually just increases the position at each IRQ,
126 * thus it can't give any strange position.
127 */ 128 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
129 goto no_jiffies_check;
130 hdelta = delta;
131 if (hdelta < runtime-> delay)
132 goto no_jiffies_check;
133 hdelta -= runtime-> delay;
134 jdelta = curr_jiffies - runtime-> hw_ptr_jiffies;
135 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/ 100 ) {
136 delta = jdelta /(((runtime->period_size * HZ) / runtime->rate)+ HZ/ 100
137 /* move new_hw_ptr according to jiffies not pos variable */ 138 new_hw_p
139 hw_base = delta;
140 /* use loop to avoid checks for delta overflows */ 141 /* the delta value is sma
143 new_hw_ptr += runtime-> period_size;
144 if (new_hw_ptr >= runtime->

boundary) {
145 new_hw_ptr -= runtime-> boundary;
146 crossed_boundary-- ;
147 }
148 delta-- ;
149 }
150 /* align hw_base to buffer_size */
151 hw_ptr_error(substream, in_interrupt, " hw_ptr skipping " ,
152 " ( pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\
153 ( long )pos, ( long )hdelta,
154 ( long )runtime- > period_size, jdelta,
155 ((hdelta * HZ) / runtime-> rate), hw_base,
156 (unsigned long )old_hw_ptr,
157 (unsigned long )new_hw_ptr);
158 /* reset values ​
to proper state */
159 delta = 0 ;
160 hw_base = new_hw_ptr - (new_hw_ptr % runtime-> buffer_size);
161 }
162 no_jiffies_check:
163 if (delta > runtime->period_size + runtime- >period_size / 2 ) { // interup
164 hw_ptr_error(substream, in_interrupt,
165 " Lost interrupts? " ,
Free AI
166 Assistant
" (stream=%i, delta =%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n " ,
167 substream->stream, ( long )delta,

https://www.cnblogs.com/pengdonglin137/articles/12772104.html 5/7
12/29/24, 9:11 PM ALSA driver--HW Buffer - dolinux - Blog Park
168 ( long ;




175 return 0 ;
176 }
177
178 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&runtime->silence_size >
179 snd_pcm_playback_silence(substream, new_hw_ptr); // Play silence
180
181 if (in_interrupt) { // Update hw_ptr_interrupt
182 delta = new_hw_ptr - runtime-> hw_ptr_interrupt;
183 if (delta < 0 )
184 delta += runtime-> boundary;
185 delta -= (snd_pcm_uframes_t)delta % runtime-> period_size;
186 runtime->hw_ptr_interrupt += delta;
187 if (runtime->hw_ptr_interrupt >= runtime-> boundary)
188 runtime->hw_ptr_interrupt -= runtime-> boundary;
189 }
190 runtime->hw_ptr_base = hw_base; // Convert the updated The value is saved t
191 runtime->status->hw_ptr = new_hw_ptr;
192 runtime->hw_ptr_jiffies = curr_jiffies;
193 if (crossed_boundary) {
194 snd_BUG_ON(crossed_boundary != 1 );
195 runtime->hw_ptr_wrap += runtime-> boundary;
196 }
197
198 update_audio_tstamp(substream, &curr_tstamp, & audio_tstamp);
199
200 return snd_pcm_update_state(substream, runtime); // Check whether it is XRUN
201
202
203 }

over.

This article is from Blog Garden, author: dolinux , no reproduction without permission

Tags: kernel and drivers , ALSA

Good article to be upvoted Follow me

Save this article WeChat Share

dolinux
fans - 343 followers - 54 0 0

+Add Follow
Upgrade to Member
Free AI Assistant
posted @ 2020-04-25 11:25 dolinux Read ( 822 ) Comment ( 0 ) Edit Favorite Report

https://www.cnblogs.com/pengdonglin137/articles/12772104.html 6/7
12/29/24, 9:11 PM ALSA driver--HW Buffer - dolinux - Blog Park

Refresh the page to return to the top

Log in to view or post comments, log in now or visit the blog homepage

[Recommendation] A new programming experience, AI that understands you better, try Doubao
MarsCode programming assistant now
[Recommendation] Blog Park joins hands with AI-driven development tool provider Chat2DB to la
unch joint lifetime membership
[Recommendation] Douyin's AI assistant Doubao, your smart encyclopedia, completely free and u
nlimited times
[Recommendation] Lightweight and high-performance SSH tool IShell: AI blessing, one step ahea
d

Editor's recommendation:
· Let's talk about dynamic thread injection of C# thread pool (Part 2)
· How to be a good technical manager
· Kafka's "lock-free philosophy": behind efficient message flow
· The design and implementation of the time wheel in Netty and Kafka
· The implementation principle of MySQL optimization tool SHOW PROFILE

Reading ranking:
· Open source GTKSystem.Windows.Forms framework allows C# Winform to run across platforms
· .NET Bios related data reading and writing
· CSP-J2/S2 2024 travel notes
· Java online car-hailing project practice: detailed explanation of the order grabbing function
· WxPython cross-platform development framework for general printing processing of list data

Today in History:
2014-04-25 Let me popularize the basic knowledge of CPU and SOC to let everyone ma…
2014-04-25 "Embedded Linux Basic Tutorial Study Notes 1"
2014-04-25 "Embedded Linux Basic Tutorial" Supplementary Reading Suggestions Elect…
2013-04-25 A very good program debugging method!

Copyright © 2024 dolinux


Powered by .NET 9.0 on Kubernetes

Free AI Assistant

https://www.cnblogs.com/pengdonglin137/articles/12772104.html 7/7

You might also like