From 7eff24a175c394acac95596b6fc6b9fdcb1f9456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E6=BD=AE?= Date: Fri, 19 Sep 2025 20:58:35 +0800 Subject: [PATCH] fix audio --- .../__pycache__/audio_manager.cpython-312.pyc | Bin 36016 -> 46215 bytes doubao/__pycache__/config.cpython-312.pyc | Bin 1493 -> 1423 bytes doubao/audio_manager.py | 187 ++++++++++++++++-- doubao/config.py | 4 +- 4 files changed, 173 insertions(+), 18 deletions(-) diff --git a/doubao/__pycache__/audio_manager.cpython-312.pyc b/doubao/__pycache__/audio_manager.cpython-312.pyc index 1270ee10b303fc0133ea34ae09657d5ff92e3fd1..815671f881e57c3bd7b48a39985077f86fac6fe1 100644 GIT binary patch delta 15761 zcmdsed3;mXmH)eMkt|uZWy_1K&60O{#drZP;FvXFf|F)tX&hn6U@*3Ml1Xe#1PM(b z@ifqz6w@}vBYBs^Z@_(B|hOjB^t@!_7w~mlHHt}bf&B} zz+LQ2-JG^MZQoC`?nvjkrJP&6i*v`l#A7p#Tb;r3G?1r_<{91bo=msSV{#|BNxRCO zxJz7Zb|+nvr-wWXwUKQ^9Qz*0C&WOH@=J+KHA2o^ySUXVw+g7*t@gyZIsAN*zh9$3}6Hl$(c?CYll;#Rd{{+#;mnqh%7L zbkURwQVEe1>oYNu>hp6>^~xoeB*?fV0O`0&IPNYP-_)5To8cx~fP{4&T|K?NRYmR?VFQhOYTGoO*2tc=ZrR<@wLYxIB4o5ZvZr-j zZ+pAPFNc$&3AxqV(eDZCS&7{0+aPCpUGb79BY1`1<>h0};)?RN% zcUP;Y%eAi4;|}XPU0z?S@=Beat)9-XVMd~LLxza75NyA8+= zE@Ua(El$Q|hO9++H-#+r>9j*ho3rq44B4{rZVqMIc8i0Fp$rS$bW!J)Rmi-BfKoWG~H^?3=!Kc?B?2ex3nv6JE1?@W)t^t8?`jqYM}8dLoBi6 z{!~d7EeZ`7tOM`>xBBI{m!`!KI*kh59vWy$qo24^>G*tYl3N31QK4gH_B**8&S#8# zLM|s8xAQ&}BX+s9l;jyQ`R)9}d>`*-_Xo*?+(W`D?m^;=rz=&adzkR8yyS)!FOsl& zv+E(0iZ*e&54<67fWIs0@a50&`?&!@PV_~`4px!yeePL4GA@MMqk^$Y73F(@X(~vS zr`$&qEO^ysJTO%nm7<0-R&Z4oJJDpr!Ip(noqbs0srN2d!&ug zm4&aVTrda%;Z{Md=!c5EDNuIl;Mk?-_Fa5t^x{AL^uqUl_{Hd>y~(lc*LQyY#J^tL zv9rz|)=x`wkKEk`!rm>fbjJC^Qjgrx<&$%viJT22toC)U>+^ZMVf6-=*X8rcausH4 zaiw;3Kj`Z4g~cVkot;i~Sk=+xcKKXkRlDrk3@tRij?JFdj;{9Zu*&Om`Fg$K=|!#d zD6zFImqLGDlncAvVz=9O?2vJ)!->lJYIAjV;==E5pye7P{kux%FKg)RhHUTrvTLi< zV@Hnx`DzFEsUh=RYUa45bfkUczHw8{Wa^xdA!Gmi@5~=|2lH!A=hsZ}+BEC={E{Dc z9qO9MuNjKJs^Tm;!&T$X`bl#`sHiMh)EFpgJQ6=qv|_0FywMUg76y!kL8HGiV5}T% zK4ZLP%D@%O**pKMsZ`G5I9PX}?lMQxtY?juDFNg>)$xsmmF2P#ozK6$S@ z9KQ_p?ww5SD(V@i+k zKo8jMx6qGN^ZnJ3@ctagUv_X)Vvff6vCbIEDjMoNxb48U(aOoJIlC84>MVZ}lM<{~ zvpGl3j}s3ihRj((b4kEl5;V^ZnCFHvt-;KqKxR=evoerb8A`W?Otzq@IAAIcnkoXO zicn@jD8n2wTCXO>ITEo$>r@JtkQ~(ctpS}isLKiHawc_oA**BeqQR9Q0YO7qtx z%l+zHlJPRfYmDb~$>XWTBTXZf<0<8nx>@H88GoIUpy2B(D2KZi6fc;?9h;?Dm@FKt zO)W+9QSBY&r*9WT8KD)y9lNyOAvi3n!Mbie>tjNw@U-k#sunkI91%E*_g=e z5*VM{i2B_w`S8)~+M{uck$h0g8rtMZb4n524mELEv1=fjJ3uzUOUo@jHGQ?sq8cDG zpCY#N$_s6n@j|KrX+Y(^X=i3`03eiGa!Y2e4_@3Y4G z)Z1vKU*2Y^VKzYW*&-F7*tuOj!)mDq)Yn?ANK-#HbxYgT53Bp&>3E-EHREO)lkdE8 z@#$Yo8xzzI7gdQ+nfm7e^U zo<8u!tFMBV(#xnU3IRMs49eJ>UY z0O-O}zen!&hNZ=udwhLivAv_SQ(g(BPHk8X5ED(545q@($qm?W9yZh}mV}wFX&dE| zWmjKV)#GxzJ#M)LtD-Vh%oSo}uvP4e7_8(dMvbWJ{#(Fi<;}2HH`G`M{dn^LV?<5X z(8`gTk-~9P{IyEP zSLZV<`?u}e23i-sD%HGy#l988$=_``mtkjF%wEqLO&%4-O;wYr)uBk0{Vn@iP$ehl ze(gnILKoT=)^o>a$04n^FHRIrSmTi9Wi8eSCp8lAOjzUvIAQ*UK(DuxOjBKFC*|c> z9mP;?1`^h_Fo$H?PNK&mUuP#Bn0FhJJR~S(OqL_&(Ty1?QQ3)E$W+ZO{?? zkd=ys%q|_y`*HE1;?Z@J*|liUvi>AyCFEXRK)CGOA7>rPVkWXQU@i@sYXjz5W+ICN znZ?1(sz7E{#6*?^OeI0n?0{)@D6=SPBD0x^v?(Uiud@YowxBLIpv#@qzFxU&WgFOUQo1uYgFY!49B$GNz9V4#D2fKX7*+FfGJtGt8uc&Nira}VftILjnuz8ephq&( zR7_9566tScw7;nOcMCq8N_Gv9Xk-2*d|9{_ao=19ZvdY5fB^sae#kR%+rc58wkzjd zsR=W{`pw=#zX@j8O9qz_u8WA=&8ldzimZoTGiXzZWkJk7{V!gy@MbSaKQU&~x!Voq z0nshKEJaKl;RcIDu1|yia%fL-mIVw&3*mfO>~n#*RgqC39Ckt+@J3nmrMaotogcbW z&+M*Cox`C4=@Jw-YZavWG!b6}+_mgT$M7H{*wfg9;s&H^EfSa^&35TwsZXQaXP6-^ zGeZ}@<3|fL)3v#TQWiF}Mm1{GjbYa2^Y0zN>*tN=?4cV1iodrUntbufKVR7QM4eqR zVV8yuUf8|=!W*w$eCyC3-yZzz@N*a5estzzru%u(-^lFObdh2Yr$P2gXNt1=nc`qt zf?;T8l~CAaTk^&%MNp^Lu_k>koC_P;ehG=c??DcMFjRh>i0-$rn*wkVxu#SFC zz7JVu$5aaTW~)xywxPFclM><}9SV9!edEQIr`RXOozmh+DK1~XwFyHji#%Jwleo>* z%pBw(%G zs|D+lY96W@chpQ8=7i8@)dn23hl?g0iP-R1yuHiMS+j>LUT7OBdcJ$Kf5N)pGUpf5vWG~>UNllMa>q#ji)+X2bwg6f zXgQd4ASq}p3mD5rdMAz5=ghVt-$DNY|Ae_5P1n*u<n1Yi!}Al8ZF`$Smi*x@ zBgrFmFIvVeHG3CN@$qRk<{1_TjKx7?dB9jcDjoKY8_Ula7k;UMMpLDnqiXlSS66GI zE@E7o?VQm%Zflt|-aaLYnGOgC1uf+POL@>z7qHY#S{i2LR0b@Sql@iFs>UsqXDqjV zHN}%m$61U0>#)%}l?;9T^=b;I&!lfJwfVpHu7SCGWTA7ZmOEb3ln%F(f^~5of6~q) zpJ!XDmfjWTENKwmttZGg@Jl)MyYnUBPYGD(lnV1tsRiV2JHHc38vv0C?udDM8^yvK|5M02CnxaVHLJa1ko z!#12hQgNs#kWo6WFP&0J31uNauIti(wKQn02v{o)=Zsq`Cam-KYC{>0alPZKa|Yx7 z`hE3))e_3i&*oTD~^e3pQGwq`-RaI`pWfl4^W5#W!h zB%s&0;Ajt+AY#yEzY_BXPPzJcr_hVRl?yw6aPgJrF1+&$%<+j<=mp zHwDw3fpljuy*!X!KAB!I#S6)%P^vMQS`bJr2&T>sq|Qc{N8&QfGph!ns>JECzPhUA zj8?^eAjzh)shJRDOE!J&U54S!S4~X?+|dF<(>&p50|9!CY($k5c+N2FG4B{)C5b>J z`CerLmg7we0MHKFiD)=LktNA){$(Lj5wKLYNY5LMw4=$a1=u6uzu06X0j!FGONcVy zfWn1n37XE2PLitE0ofOJzj5)qqnDoB_4(WM!eg&p7<}`>?$Md(L_rQQ)q`=B{}#pg zXTX?9mr5)cqPsGKBn*f!tRh2C*TM_{CvBY`m+a&fh=D-Hiz{nd9m!jO@6Wx7AWVZ8 ze+{d>Lzc<-{E@0x8-LOWPRqfp16h|jDZ#W?n&QQ4B%wF};kdJU;&`P&yzM{rmdShcx-oi8QU8 zOl=8+fPl*g0)q1KqO~cHKbmJ-pq7rQ2+(VcSkz0I&*VchLqgodhYOZnF-O78_rs_} z1OgltlrX&f+(2}L07S^lAUgUFu%oeE^hGz}(67jZ`U4``#fXStZUf{FTESh2ba`!$ zFni#Y@B>0W7{VL-^K~N_q!0YhB$_2ZC*WvX6 zf>s$qMu6GDma_Y_E%oD$i>epZ>4i6+{`~0?w55+fb@7cu7?}nNe)luGFaGccfVM9@ z{?vuheV^}s4C=_Upv5J$?U!)5F#CFA(};ZqT^1HLcXTPpx*HnE7>xwm3N~DEz^5_t zI>-*|FbdVGgxS5a53^M5t~S`PQ!MUvP??32`txokOhqG|fy_E+obMbdK1>cfel9@sqIpOB zszA|_iTtI|iEEe~Xd7B`TAzb`-Abn7xYVq1oh{Y8F_8V|>zr4B=QZK|VtQdd(7=R%H83oC}u zmG@fcZ(#H8NIi?|sz9!%cN3M(F#2D2#q+)-`eD5-HL^n7{H8@P#pXy&+PU07Z+Sd{ zrWU1%au)P@s6UGa>kUbf7F~cp!EdKK?$0RO1dA4f#Ng43?EnM8O~t4ryFl!X+f}i! zuUn)|D-C{WyXs+8AH;C+ehpwmIC1g$9T#7J^3t;hP=xP>4Ea$cs4*3Pk(DU5V!|sd zVKo?W>f}|}WHpi|AYs9^&Knjtdt6;|36tj@EJ7a={KD=Y*@?**id4s(L77SWbof%) zq}I5$u5VRXZHE`!M7HCth`qAqhEOwtHCx>tpQjBr88@!GeE&uci zIA^jPEIm*Xy7{3Rpu>74Co7k`jUXYWaN%XeL1wAzkmei-F5qL7f}0&z&^Zj;~p}dl}R)0|;x`&Fl;l@7kFS$&GDE(>&AK5BBWx!RlRhvYc%LEdVlR%v#lzqFd@pKi z*kJzRr@y%H!sB1OzU$(fdl^DuDmzx={z#RW*z4p0=tKq;J-xvwBD_Sz(e3rf4$N*w z5<@9FF&P#07pFl9hBxTnwH1B?Xd3ScNGX0!RY<1~>aqg5tVx}N@wf*F5mX3Z1e5Hi zlk7~4909!}sLv1R^C$I%Gja+7`hrQllT~({PI9oK?0`NysE-t(6e>9=izSnKaC8!% zTDoWH;Ihw>()ap?)=nlBLA(7)`;vnCynsIMjJ{w>;Pk~`(ZPHN_~(i^nHJi(<2KF0 zM&WotA_`TV1U!7-diWTOC*cIkdL#&5WOQj{bS>mEB)21J2NIUpM!MXK8O#FqAr~8F zglo*4$xi{t%TLn};w^qF@ZJs}ySTGr-IQpM@`u+`d3NQi#yvxM11$Ok>UCD|6|mJpA)RhVdZt63rrju=Hn-K~KX4hg$h z3dbgv!a-6}TBsR|^kTcHmiHA$YHcimWn%I}VMZj2b&4~@E|x+FrKIAaCVoIH1>kNv zg^#dYlfofp7wZLWX)Ki$O~nsXbFKDB(zh_eZCnuHVs~FOZ{s5RWq%r30`G4~0cC?1 zxE#wAj-yBP>GT1!8V_&f(<72C-+R@EYldCEJ0hH0-@*B!U$pTX^tR-T_!*_NJGnfq zC{o*ZZ-jH}aE?;0)g7R^?!x_6vWf;CuokOi!;A(A5nBxVmUwIo(ILCK;(hnh@dc@c zZk%eAZFaF#c_cMs${t`JzK(85G1Ny5JhViYh+WunqdSs{-CHXoJeIQ;?LaL_|Cl0? zWcsI+eEScehWtGwKLiri^t5em^;Xot!3;#DaucmFEO+b)_965C1?Wde1tb$EQ3=E}1ht6vGS$qaQSUy0X zH53)G7eN^gi@m)a?y!WkN`4+|pxq9u+B!Qta8Tzt`lZ1*mXW%JBq^@ka;%aKgg&2E zqEmKOQCG+g`fq99xS#D-Ij2Fx_c5P+ID3Bd>zOj1K9Uo|2Tb|&r!VSob#|}6Q#l`3 z)(Yo)I()6I#i)y|bWb`JLe&jpIT;CL7KSxT1D4XD<(7cumI=#(-M5`hvYgYWji=9= z)Wc5U?7iX{efDRVv3gR!hPD`&iFus9knU8Q$=~QLY z8J-f;W4OqodaSGQfBgIu{QL~|*l$%iO~mCn}HhA8!oQeq+*d=Q)f0;PL~@hrQ3XOsS#zluk&iV;daKfYBK=Rt1bz zqpK(3_*y*&TRYv~?*6k@msUT;0r~6I*_g$V{O1#``0N! z1tovIsv67A9w2@kSz5F>m3ybjv?v$c!X^hKj@OzO&EihvN{dR>C!A`?IWbGKI9WJR zo48mfoK#DYb5bWk&dFo}`P8cB2I1YfriNv+rT3)VTZ_c^oCNtI&9Zp)dzFdHRODszdzK|b#vhLf2 zmu+L_hITUR3v8s4{~4?P8cDQyIH7HW%hxKq*0=gR5BXvpE$8R*^uOl)ErC_thaJF# zQB9+j9Hj+~Is81Hu4wG8J%QaZ{qPEM+kngnc+1$ZKjm5rhfYcpKX$dzA;zD_M!!e$ z8MQCUC%+q8x`-#_CAxgEwfzs6&z}ENGLwu3Jqw+YFk^#81c(C#jp*)pK}5#)qLKp|fFeR`C=4er%s<#Jdx4>StIS4R zYd69#Lg>q@iukwqvCyjj;8UVKMuPQ|^vv33ew?S--@HRzm&kF=9H9r*rMQ_i_Ubnc zf^ZmiGqyiaF!qNB_Nr*gnsoZ``Z*A;rf;opB?a`B1$H=vUqBl=G<4I31X4)*HaH5L z{VMRw;x`q-xL9LBX?KyY3Eq-jfMp8l(G3Q3@v}k~R&iasfgj&}5r zH>hJ{Ms1veH|B7ArNQ?Zef4@U2POBPkS`3byP>r(SQ@Rx z4^BZXe(<-9jxjoTLkoUz*^Cz1P>T${NB_8SDJh|IHft{1c$B9jh!$L1VfMd;Se734!Y zve{4Gq=j8;iH&}%t2(=1!`4$7cq(B-kE_?~X?1sa+g!4{wXM4se1kjbpSm{t8LD9+ z1E!mG3&vg5JOjXtkQ#@C2s772>lxwSe;=bW?~#z z-UoT~Kf8^E*^mmWVdbzN7O<6`$d)AjU;tLnW?5PBw6>?5Owf*=J5(<0uZ14z`KIa& z56k3>v79X*ini>awJcyQ3tHy~tn=UA8f?5T(0JeYss{p%t_kb9G0j#j?>Cd9+N4#m ztDM=SU27)Ca>%L@)v;U)@W(l_s$6xP=#Wn=L)u_kHCs55o(KGida|lfJkj6){-l+x z=Eak?rZ`BvTVP+4$(>R+C9Rf(_tGmM@xGd@P7&XaTUZQ<4=c&)H1WeK5qbYy9-4eu zXN1H@DdyEi;iJ-~I7s}unyk)K{kp~i{BKgo>O$3T40*`UC98|Y-_$yRAI~PM%f#^< z>}k9JI~sTDkgu*@T_FUDW&?lPLRQZgPg|R?qlsFwhKLh&*kEElHtYZBII zgfsKV8c}s-ep3k~f<Ys~Xg2=U`5lha5i%OVa8j_{D<;8i&&eQlqpwTOGEt zoI;jU%xD>-71HW@b+`sgKPH&-u}I(*KUOoUk=CTBKTgEg{Wyb_W@^?Ng^#oI*BXR# zab#`0>YPSGK2d^~h(BkLp!l3oSZk(xmu1BJK(m34#Aq#?S}A6Fvb+DJNUG_7`K$1( zUlBV){=0P;rH!v7eT1osXBagp3W3ozjFvO1nZpg9gTJHjcZh!9KZk6k6MpB-JJr&P z9ZuEPDASwh13Q-ajm%Oo1l0whcm*z?u?@$!!GiF?uhjsb$_coP{*KL<{roj@3~+$& z%gN=qtPI-L!CLW-&vLxEK|WXaKpV zkx(GlYzN;)yLK9rHwuv50gLeqJjOgFW{vIN`AcG+70`p5KYK=q)fvz`&*+P%B-;9D zHu(#E(Ob`N+8nB_|5B)x3Wjrsy(0^UA39Vv z#X<6jm)*ua8`wRR4(B!?J5*V71@D))l3R&nzkDD4!?&K$I;0ZixkGfvV@9%`>i1-h zz4q8Wq!`21?DRFBW56Hi$r(VxI)Kz&02@J?JH69rj8^V0FQ~;Tbx2G=yda^RJ#vTv z&)dsLzAex_yB{O2G5wxd#NPlp{h3Q#u=(Y-`?~F3*H(`mroaxrAn?G?6sFx6_FU;f zxx)v)!dlkCz&ez<@CEUKVbZPuNQ@7`GnLIX8Gfn3F|r?5iwDZ!M{4nD=i(B^6Z0qI z3PSXqCkD%{3b4jGf&2&Aac_$=9LLdYPkAM&q9rKVjraMVP(w(X95Q4#= z3li821TKn<>j=y`$Oj7AIL`VQdCJR2dcdzk!8+=U2;;Z=MVW7PoSoS{=XN>)$G`Ub zw!ZYQ&N=toQ}>>G&b_B9TW;~k_VQ7eA|tgNTb&hL_XEF`Qw39M}Bf^>B&^e8cNC#(Ibm z+po4o&>_VDaZ^#S@;;HS$TQKBBDFBU*?C$eWX|d54v}RxrIZ4Ll}rG#s;9rT*WvQW zs)qhrM(AAbo?f5b>ywa%#f8A)_Gq`i`vN3l^7}kwV zuNo4rsFTJjXATJ;tCJ-oK0zrteZ7*K_S7VZ0^ztl^wnA;9oQdF-zZO@jd=$8n{oq9 zJYb}6mg{M5Y&`EEG}>sSX;J#9Bm7|zjKBqRP|*!W^WgoQP0?!r$&Ib_i?=u4dcl9| zz|Nb$rC)4*@y6>7doUaMZh(#4xROh?zOZ!f(x9m@U@9Eb z8-x1HfIc&*FAV4l#|%k9Lw3NB9W)dN48>!yhG1-ZAT~W1TNH>b8jDL9Gp7g5#Q}41 z&|DEPSByt+sYSOrWvZ6Bb3BTRi4R6w0@0RHwS_sg4g5%bHF5vH4&CzR4;?Dyz;tD0 zC?+HuFcU76@_=R$CH`xHFcvbQCe zS`0$rGNm2BNK_YAf^PGIS-E06%sq0P%PGHvpkX{gWpluAQIHJ)FgH8^{3h zl40clp`+$_$gKzkS*@b2Gfax%9D&w8XryGoq$XTHvGKi$bWVw3!Ohn<-FR~Zvkv1( zLRZKUUZ1BYoMK{Im&fZ2MWV*%l)7DRh*}%Z0!~(j5|JJ*DRs<(zTTw(;3Z>9(3l%A z=Dw5}%&QLMRgWgj`i4_z(uNku(T1^@gkVg1ASV4vOeWBKbUSrVM~$nXd0fqDB6sMv z>Vj%>KyChbBA^cO5=@U<20O@TX>w{N(4he-?`QjfRDhCVgbHdaGcCZ)!;9nD#9bAt z#syKV-q$?N!RR8PEd+g{~Kk$ zCPe3VmzNPzPWM-2^FA~Eev64(?=iPKl-2M6hYC_Z76^7Z)WF5v#p& zF4k{ynSD4DcC9X*hy|1UA{v{gS8%KAX=!C@#J!X9WjFznOOKYD>%D*U z-5+l7JrJfGQ7+CmIj7YRhUHWDe1pe>drPNxIVCNI5yeYYH#zn+g%-@ zgi`giE_VA$r~Cg<^;41}i$Cpk_QDahg54rQ`bh>^ttN$X2_x! zM(Tt81P>$$Q$%9ZVPXS9FEcT(g*@(#{$)IZn6KWb-i^`kB3e zUaN^ApHs_FDt%$D-fx<-iqO{{Fw(r_czPl)g1%OpVvX(>`h^Ux6!!i;o^Xv24ul*2 z**Zld*GDqAiG06rZZS<8GJ}~SqNE?r%_xq5Wfx$y>~bK7Gn(S2wgha8qn3FFoi1E; zN#+5%Vx@sTGDl^Y+#h_=lLjK`$-MX^M^re(2&aLX&6hi&KzANAbULDOS6C1A#|D)n z2A(mweK?fBVR6GQcMZ&9GPpB2DRG1Pjz`4~sGsAW=ck_32xa63_2X)HM(9pW^S4fm zyR&_S46nM&;;OqW>O&Uk#;3BPf8Zsmt8+$zZLsj}g!RYk3gW-~`Ch#Ktp?&;<#TmA zAw22vy7f`F*kQ-=bb<6RUAbU6e~YItF32D3#XTuhT;169@{QfUy|sJq&7()FEVg6` z4{E6$KvrPJ`~=yR$f`P9y{$f>#&d>=c_DL=%%@kcuHw1K- z)7c|Am`+`HkFQ^{SE7Mc2oED*Qb`>MO$dzuvZiibo3qE~@_+>=_OfZD4BEV~L?>%Q zdE{vIwbGG=@$}F_Q=&|qUJdjMK^QezOvTkb-7_rbhp7i`e?t;>6Pw7o0DNV z6^&ETBUPbFD2CzvM#5v04Mo;MNZZ|>zE+oyg`~6*n^qt^hR}>)M|cEJC8-60MJk)O zIyCPQlHEo$$9r{{wC9q~sUaNhx6sAq^t1o&*IK6?s^hir(k3~*JsvkOFQPu1TLV&TDHj7JD_vet_QB9$TVhAyRIuR& z#atst&BIvf>T){jB*`POcx3|(2ki*#`53jz?kav2@z3r4oYzQZklA=Sk$$}~Q57l= z@@aj~e10qOkMwL54QsIzdtrPIDGA_~mS(NB@wW(VSUaFw01{b%D#I&z=-AphgKP>v z7~xcU4WJda_QOa`uBxo@w)WdQVFDhB&03g>RVQj<;U{$g$Wftp`7W0iqRJ^r7-Agg{%& zhUD1?@NrO?NUokx{)?gh=TRDy{`36dSqit;$|EL zR&8t);c>jp(cf>(<1Z6`#1mifag(l}combjQuU@K{7ph1*t9~E2P?gVBa@#qO#aU| z=@p7&8jc>@lH*Ss8d1W#;Y=*z>DBESN=Mw0oWnf*`*yn`7w*JmrjPHKMQrr#9afS@ zKiOfNmG8r>XV(DdusI?QW7@&xh+Gf&9Oo!_UNKcC+^tQ^M%Iu<`iqgYN&BCSY#uz? zFZPQ+tiDE+!(6ETs^mt*;gbvx{)3h{{NNp0)l4h(AGCyF*QAy(JP))K!%bnWhH$|L z!mLR(e)uM+@xvc7Jj`%YxXWY@ez^9I9?76ZhELG4T?*$xe2T2R+{c9d;JtLNydJ;h{*Zr`&)iFpG1;1_!yR{jTpl=-87 z(X;Oh$(b)S?`=Mk5VXw=*yf(74A_>8wsk(+d^y$SFMD3g59-NDZFHkiaWbh^+oC6@ zGDu^l@>He?=+hi&%u${uI;5kD5UZ0L^Au+ivVcA_lQdQeXR570pG_r=Rl-?wts0p3 zaxBfU+&NWkbmJ_=`GitnE~rS8R=A*^mk-SQ(@0aK@P4^~^x!=_ba}rj5tt9+Qkr5E z9~9QAf%&k4G^Hv(oNfa8qd3xJQGTS)Li!%klp%aH!v^$dI%&!lMl;aTXbu`0wds(q zsA#e&0(oUX|IS33rVGDItwlqZXON~D!sROLaCtU%7`(!v)|IkaMKe)+3=geVemuRl z0GJ?HuTcgwM5J?ZOu-WD5}bxT#=&q{<)VyjG8?CCV zCJoX#1Tjx+ELUAEW|At943ev}#3q$W<~7h+jwFaNVpFn8HZX~WNirB_Gqj0K(^PU1 zYn{O))dYqp*C1XaVzX9tO^L(37LBdfVl^!>ifhT)EfI?A9BEM~uM-hzr3eGkU5^l< z`Fe~37`mb(foT2B`+1S1(2;{iy4a_OFK61ae$r1^>OaPiV+sBW!&-)hN^bZ+;RpNE z@UP(a6#f2Jm86-L9kktTik>-WQ@)O|D$&~q7Y`cQp}?vsx3g`c62S9Qj%b5i@Hy>R zv`Uw-$D0W3NMscgt0mq+**NM)wY%IdZzmKLtaOpE-hdCuAt4lNXdX%$sSJBy&dXw# zhrabvQXwlSF~cObDd6Xc@HxWHKzP@H(eGeO6}82{oXsTlS;E;YY(G04JHMwV^|``(@wrG>llpw&y;<0LE(%-E z<&*kC;aq_U=<{k)KUgfB*I1FsBlV@i`TSZ9Fc->mVJsI-1n7$}0>E^JSqyU-f+dg_ zGAw3T%5a)yNxb4>b<~n*#U(Agad4NSMUY&IS0HV)E#(yNa|*C;6J$jae7<27vUD6B z{4T2A%vF^+7Pfl4aERkbQTi$A}To%&LX^x za2)|19;%@dkTN3Rr)+6P7_h|i!lp|bUQVj25Oelr?(@DhZ{NE8MdKW>Ct%IsHtOtT z_pyYeaRu;W)283X`!{YfpNN)k8t5-y-j-nz3qp@T>#`a@S>X$sPb2YAb=N(45))bGx-w5 z2ru$<&atP+X4>#dlK<0VM#BG%qknnTQio9UMa#rB>AW0D)Dp>;SAs_6kQ!{RPT-NT<;O ze|`dU`hMi`3lAGKSf}s!OJZ?_RA=a-sfNxil77Z!*nnN6a KJdQRTul!#_jwc-e diff --git a/doubao/__pycache__/config.cpython-312.pyc b/doubao/__pycache__/config.cpython-312.pyc index 59a6393f4b2e2ab20d338f0cac9ec2f5de0fc5a7..440ea3073bae1e4b905399cbb0a8213c0980a499 100644 GIT binary patch delta 189 zcmcc0-OtT;nwOW00SJPF&Sr4(OyrYLS^?xuXGmd4Va#EOVn|_1VNPL5VNGFUVn}5K zVumc1i2>S-%oA&@RasKxQutDMQ{+<=QWWQ~MzKQq{7^nyC8MU&W){YeOacs&3=EkK zb_@)+STplV49zD0W7c42zr|8onwc`$jKz3z5lfAzF3@U5ATB-yBt9@RGBVy~;GWFJ Xx^VJpR!QEE+-%}Z7a4?$w1Kh!+b=78 delta 279 zcmeC@zRJyanwOW00SGF5&SsqDp2#Pmbpyzo&XB^8!kEJl1)&+E7*m*1m{V9%SX0=T z7*d&lm?4X8qK7sk%fu3EU)B`46uuPR6!}!fEFO?)s31jQ4r>%UR1H5KH5`?Unu;5* zd}QKm02-6oV8_5P`6{!90Ou{1($dV7TkHjuiKQu-`IA{#j5*i~5X$RJ##1Jn%wdoDeN diff --git a/doubao/audio_manager.py b/doubao/audio_manager.py index b85ce38..e72ef19 100644 --- a/doubao/audio_manager.py +++ b/doubao/audio_manager.py @@ -35,13 +35,26 @@ class AudioDeviceManager: self.input_stream = None self.output_stream = None self.audio_queue = None + self.playback_queue = None # 播放队列 self.recording = False + self.playing = False + + # 预缓冲机制 + self.pre_buffer = [] + self.pre_buffer_size = 5 # 预缓冲5个音频块 + self.buffer_threshold = 3 # 缓冲阈值,低于此值开始预缓冲 + + # 静音检测和回声消除 + self.silence_threshold = 500 # 静音阈值 + self.echo_suppression_enabled = True + self.last_audio_level = 0 + self.audio_level_history = [] def open_input_stream(self): """打开音频输入流""" try: import queue - self.audio_queue = queue.Queue(maxsize=100) # 音频数据队列 + self.audio_queue = queue.Queue(maxsize=100) # 增大队列大小,提供更多缓冲 def audio_callback(indata, frames, time_info, status): """音频数据回调""" @@ -51,17 +64,23 @@ class AudioDeviceManager: try: # 将numpy数组转换为字节数据 audio_bytes = indata.tobytes() + + # 添加音频数据预处理,提高质量 + if hasattr(self, '_audio_processor'): + audio_bytes = self._audio_processor(audio_bytes) + self.audio_queue.put_nowait(audio_bytes) except queue.Full: - print("警告: 音频队列已满,丢弃数据") + pass # 静默丢弃,避免阻塞 self.input_stream = sd.InputStream( samplerate=self.input_config.sample_rate, channels=self.input_config.channels, - dtype='int16', # 16-bit PCM + dtype='int16', blocksize=self.input_config.chunk, callback=audio_callback, - device=None # 使用默认设备 + device=None, + latency='low' # 低延迟模式 ) self.input_stream.start() self.recording = True @@ -73,14 +92,53 @@ class AudioDeviceManager: def open_output_stream(self): """打开音频输出流""" try: + import queue + self.playback_queue = queue.Queue(maxsize=50) # 增大播放队列,提供更多缓冲 + + def playback_callback(outdata, frames, time_info, status): + """音频播放回调""" + if status: + print(f"播放状态: {status}") + + try: + # 从队列获取音频数据 + audio_data = self.playback_queue.get_nowait() + + # 转换字节数据为numpy数组 + audio_array = np.frombuffer(audio_data, dtype=np.int16) + audio_array = audio_array.reshape(-1, self.output_config.channels) + + # 应用音频淡入淡出效果,减少爆音 + if hasattr(self, '_apply_volume_fade'): + audio_array = self._apply_volume_fade(audio_array) + + # 确保数据大小匹配 + if len(audio_array) < frames: + # 数据不足,用0填充 + padded = np.zeros((frames, self.output_config.channels), dtype=np.int16) + padded[:len(audio_array)] = audio_array + outdata[:] = padded + else: + outdata[:] = audio_array[:frames] + + except queue.Empty: + # 队列为空,输出静音 + outdata.fill(0) + except Exception as e: + print(f"播放回调错误: {e}") + outdata.fill(0) + self.output_stream = sd.OutputStream( samplerate=self.output_config.sample_rate, channels=self.output_config.channels, - dtype='int16', # 16-bit PCM + dtype='int16', blocksize=self.output_config.chunk, - device=None # 使用默认设备 + callback=playback_callback, + device=None, + latency='low' # 低延迟模式 ) self.output_stream.start() + self.playing = True return self.output_stream except Exception as e: print(f"打开输出流失败: {e}") @@ -89,13 +147,42 @@ class AudioDeviceManager: def play_audio(self, audio_data: bytes) -> None: """播放音频数据""" try: - # 将字节数据转换为numpy数组 - audio_array = np.frombuffer(audio_data, dtype=np.int16) - audio_array = audio_array.reshape(-1, self.output_config.channels) - - # 使用sounddevice播放 - sd.play(audio_array, samplerate=self.output_config.sample_rate) - sd.wait() # 等待播放完成 + if self.playing and self.playback_queue: + # 音频数据预缓冲:将大数据块分成更小的块以获得更流畅的播放 + chunk_size = self.output_config.chunk * 2 # 每个样本2字节 + + # 预处理音频数据 + if hasattr(self, '_playback_processor'): + audio_data = self._playback_processor(audio_data) + + # 预缓冲机制:在播放前积累一些音频块 + if len(self.pre_buffer) < self.pre_buffer_size: + chunk_size = self.output_config.chunk * 2 + for i in range(0, len(audio_data), chunk_size): + chunk = audio_data[i:i+chunk_size] + self.pre_buffer.append(chunk) + if len(self.pre_buffer) >= self.pre_buffer_size: + break + + # 如果预缓冲已满,开始播放 + if len(self.pre_buffer) >= self.pre_buffer_size: + self._flush_pre_buffer() + + # 分块处理音频数据,避免单个数据块过大 + for i in range(0, len(audio_data), chunk_size): + chunk = audio_data[i:i+chunk_size] + try: + # 使用阻塞式put,确保不丢失数据 + self.playback_queue.put(chunk, timeout=0.1) + except queue.Full: + print("警告: 播放队列已满,丢弃音频数据") + # 如果队列满,尝试清空一些旧数据 + try: + self.playback_queue.get_nowait() + self.playback_queue.put(chunk, timeout=0.05) + except: + pass + break except Exception as e: print(f"音频播放失败: {e}") @@ -105,9 +192,9 @@ class AudioDeviceManager: if not self.recording or self.audio_queue is None: return b'\x00' * (frames * 2) # 返回静音数据 - # 从队列获取音频数据 + # 使用更长的超时时间,提高音频数据获取成功率 try: - audio_data = self.audio_queue.get(timeout=0.1) # 100ms超时 + audio_data = self.audio_queue.get(timeout=0.1) # 增加超时时间 return audio_data except queue.Empty: # 队列为空,返回静音数据 @@ -121,10 +208,75 @@ class AudioDeviceManager: """停止录音""" self.recording = False + def stop_playing(self): + """停止播放""" + self.playing = False + if self.playback_queue: + # 清空播放队列 + while not self.playback_queue.empty(): + try: + self.playback_queue.get_nowait() + except queue.Empty: + break + + def _flush_pre_buffer(self): + """刷新预缓冲区到播放队列""" + if hasattr(self, 'pre_buffer') and self.pre_buffer: + for chunk in self.pre_buffer: + try: + self.playback_queue.put(chunk, timeout=0.1) + except queue.Full: + print("警告: 播放队列已满,丢弃预缓冲数据") + break + self.pre_buffer.clear() + + def _apply_volume_fade(self, audio_array): + """应用音量淡入淡出效果,减少爆音""" + try: + # 简单的淡入淡出效果 + fade_samples = min(100, len(audio_array) // 10) # 淡入淡出样本数 + + # 淡入 + for i in range(fade_samples): + factor = i / fade_samples + audio_array[i] = int(audio_array[i] * factor) + + # 淡出 + for i in range(fade_samples): + factor = (fade_samples - i) / fade_samples + audio_array[-(i+1)] = int(audio_array[-(i+1)] * factor) + + return audio_array + except Exception as e: + print(f"音量淡入淡出失败: {e}") + return audio_array + + def _detect_silence(self, audio_data): + """检测静音""" + try: + audio_array = np.frombuffer(audio_data, dtype=np.int16) + audio_level = np.abs(audio_array).mean() + + # 更新音频电平历史 + self.audio_level_history.append(audio_level) + if len(self.audio_level_history) > 10: + self.audio_level_history.pop(0) + + # 计算平均音频电平 + avg_level = np.mean(self.audio_level_history) if self.audio_level_history else 0 + + # 检测静音 + is_silence = audio_level < self.silence_threshold + return is_silence, audio_level, avg_level + except Exception as e: + print(f"静音检测失败: {e}") + return False, 0, 0 + def cleanup(self) -> None: """清理音频设备资源""" try: - self.recording = False + self.stop_recording() + self.stop_playing() if self.input_stream: self.input_stream.stop() self.input_stream.close() @@ -132,6 +284,9 @@ class AudioDeviceManager: self.output_stream.stop() self.output_stream.close() sd.stop() # 停止所有音频播放 + # 清空预缓冲区 + if hasattr(self, 'pre_buffer'): + self.pre_buffer.clear() except Exception as e: print(f"清理音频设备失败: {e}") diff --git a/doubao/config.py b/doubao/config.py index c388772..ebde61b 100644 --- a/doubao/config.py +++ b/doubao/config.py @@ -42,7 +42,7 @@ start_session_req = { } input_audio_config = { - "chunk": 3200, + "chunk": 6400, # 增大缓冲区大小,减少处理频率 "format": "pcm", "channels": 1, "sample_rate": 16000, @@ -50,7 +50,7 @@ input_audio_config = { } output_audio_config = { - "chunk": 3200, + "chunk": 6400, # 增大缓冲区大小,减少处理频率 "format": "pcm", "channels": 1, "sample_rate": 24000,