c++ 如何获取麦克风收到的声音的音量 根据声音绘制进度条

SuperCoderJz 2014-06-03 05:23:47
麦克风接收到一个声音信号,进度条上则产生一定的变化,声音消失后进度条变化消失.
类似于qq的录音功能。
我用wave函数实现了接受到声音,接下来怎么处理呢??
...全文
1039 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
fly_sky010 2015-05-25
  • 打赏
  • 举报
回复
mixer只能用于xp平台,win7下使用com组件
671coder 2015-02-06
  • 打赏
  • 举报
回复
顶一个~!!!!!
SuperCoderJz 2014-06-04
  • 打赏
  • 举报
回复 1
引用 2 楼 zhao4zhong1 的回复:
mixerGetControlDetails The mixerGetControlDetails function retrieves details about a single control associated with an audio line. MMRESULT mixerGetControlDetails( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails ); Parameters hmxobj Handle of the mixer device object being queried. pmxcd Address of a MIXERCONTROLDETAILS structure, which is filled with state information about the control. fdwDetails Flags for retrieving control details. The following values are defined: MIXER_GETCONTROLDETAILSF_LISTTEXT The paDetails member of the MIXERCONTROLDETAILS structure points to one or more MIXERCONTROLDETAILS_LISTTEXT structures to receive text labels for multiple-item controls. An application must get all list text items for a multiple-item control at once. This flag cannot be used with MIXERCONTROL_CONTROLTYPE_CUSTOM controls. MIXER_GETCONTROLDETAILSF_VALUE Current values for a control are retrieved. The paDetails member of the MIXERCONTROLDETAILS structure points to one or more details structures appropriate for the control class. MIXER_OBJECTF_AUX The hmxobj parameter is an auxiliary device identifier in the range of zero to one less than the number of devices returned by the auxGetNumDevs function. MIXER_OBJECTF_HMIDIIN The hmxobj parameter is the handle of a MIDI (Musical Instrument Digital Interface) input device. This handle must have been returned by the midiInOpen function. MIXER_OBJECTF_HMIDIOUT The hmxobj parameter is the handle of a MIDI output device. This handle must have been returned by the midiOutOpen function. MIXER_OBJECTF_HMIXER The hmxobj parameter is a mixer device handle returned by the mixerOpen function. This flag is optional. MIXER_OBJECTF_HWAVEIN The hmxobj parameter is a waveform-audio input handle returned by the waveInOpen function. MIXER_OBJECTF_HWAVEOUT The hmxobj parameter is a waveform-audio output handle returned by the waveOutOpen function. MIXER_OBJECTF_MIDIIN The hmxobj parameter is the identifier of a MIDI input device. This identifier must be in the range of zero to one less than the number of devices returned by the midiInGetNumDevs function. MIXER_OBJECTF_MIDIOUT The hmxobj parameter is the identifier of a MIDI output device. This identifier must be in the range of zero to one less than the number of devices returned by the midiOutGetNumDevs function. MIXER_OBJECTF_MIXER The hmxobj parameter is the identifier of a mixer device in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function. This flag is optional. MIXER_OBJECTF_WAVEIN The hmxobj parameter is the identifier of a waveform-audio input device in the range of zero to one less than the number of devices returned by the waveInGetNumDevs function. MIXER_OBJECTF_WAVEOUT The hmxobj parameter is the identifier of a waveform-audio output device in the range of zero to one less than the number of devices returned by the waveOutGetNumDevs function. Return Values Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following: Value Description MIXERR_INVALCONTROL The control reference is invalid. MMSYSERR_BADDEVICEID The hmxobj parameter specifies an invalid device identifier. MMSYSERR_INVALFLAG One or more flags are invalid. MMSYSERR_INVALHANDLE The hmxobj parameter specifies an invalid handle. MMSYSERR_INVALPARAM One or more parameters are invalid. MMSYSERR_NODRIVER No mixer device is available for the object specified by hmxobj. Remarks All members of the MIXERCONTROLDETAILS structure must be initialized before calling this function. QuickInfo Windows NT: Requires version 3.1 or later. Windows: Requires Windows 95 or later. Windows CE: Unsupported. Header: Declared in mmsystem.h. Import Library: Use winmm.lib. Unicode: Implemented as Unicode and ANSI versions on Windows NT. See Also Audio Mixers Overview, Audio Mixer Functions, MIXERCONTROLDETAILS, MIXERCONTROLDETAILS_LISTTEXT, auxGetNumDevs, midiInOpen, midiOutOpen, mixerOpen, waveInOpen, waveOutOpen, midiInGetNumDevs, midiOutGetNumDevs, mixerGetNumDevs, waveInGetNumDevs, waveOutGetNumDevs
我用了这个函数 可得到的总时一个数据啊 ,我用的定时器,不断调用这个函数,函数如下:
int CAudio2Dlg::getAudioInputVolum()
{
  MMRESULT          rc;     // 多媒体函数返回结果变量
 HMIXER            hMixer; // 混合器设备句柄
 MIXERLINE         mxl;    // 音频线路标准状态信息结构体
 MIXERLINECONTROLS mxlc;   // 音频线路控制器集合信息结构体
 MIXERCONTROL      mxc;    // 单个音频线路控制器信息结构体

 //枚举所有声卡驱动,这个枚举很重要。很多代码调用mixOpen时只是用了第一个设备,即
        //mixerOpen(&hMixer, 0 , 0 ,0 ),但是我在这个设备下调用mixerGetLineInfo出问题了,
       //可能还是跟声卡驱动有关。
 for( int deviceID =0 ; true ; deviceID++ )
 {
  // 打开混合器设备
  rc = mixerOpen(&hMixer, // 返回的设备句柄
   deviceID,       // 单声卡的设备ID为零
   0,       // 不使用回调机制
   0,       // 回调函数参数
   MIXER_OBJECTF_MIXER);      // MIXER_OBJECTF_MIXER宏的值,表示任选有效设备ID
  if( MMSYSERR_NOERROR!=rc )
  {
   //跳出循环
   break;
  }
  // 打开混合器设备无错的话,则

  // MIXERLINE 结构体变量清零
  ZeroMemory(&mxl, sizeof(MIXERLINE));

  mxl.cbStruct = sizeof(MIXERLINE); // 微软用此办法判断版本
  // 指出需要获取的通道,声卡的音频输出用MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
  mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;

  // 取得混合器设备的指定线路信息
  rc = mixerGetLineInfo((HMIXEROBJ)hMixer,
   &mxl,
   // 取得MIXERLINE::dwComponentType指定类型的第一个音频线路信息
   MIXER_OBJECTF_HMIXER|MIXER_GETLINEINFOF_COMPONENTTYPE);
  if( rc!=MMSYSERR_NOERROR )
  {
   //无法获取声音输入线路,尝试其他声卡
   continue;
  }

  // 取得混合器设备的指定线路信息成功的话,则

  // 将连接数保存 
  DWORD   dwConnections   =   mxl.cConnections; 
  // 准备获取麦克风设备的ID 
  DWORD   dwLineID = -1; 
  for( DWORD i=0 ; i<dwConnections; i++ )
  { 
   // 枚举每一个设备,当Source的ID等于当前的迭代记数 
   mxl.dwSource = i;
   // 根据SourceID获得连接的信息 
   rc = mixerGetLineInfo(   (HMIXEROBJ)hMixer,   &mxl, 
    MIXER_OBJECTF_HMIXER   |   MIXER_GETLINEINFOF_SOURCE   ); 
   // 判断函数执行错误 
   if( MMSYSERR_NOERROR==rc )
   { 
    // 如果当前设备类型是麦克风,则跳出循环。 
    if( mxl.dwComponentType==MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE )
    { 
     dwLineID = mxl.dwLineID; 
     break; 
    }
   }
  }
  // 如果没有找到,返回失败。 
  if( dwLineID==-1 )
  { 
   //尝试其他声卡
   continue;
  }

  // MIXERCONTROL 结构体变量清零
  ZeroMemory(&mxc, sizeof(MIXERCONTROL));

  mxc.cbStruct = sizeof(mxc); // 微软用此办法判断版本

  // MIXERLINECONTROLS 结构体变量清零
  ZeroMemory(&mxlc, sizeof(MIXERLINECONTROLS));

  mxlc.cbStruct = sizeof(mxlc); // 微软用此办法判断版本

  mxlc.dwLineID = dwLineID; // 上面取得的声卡音频输入线路标识
  // 控制类型为控制音量
  mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
  mxlc.cControls = 1;          // 使用 MIXERCONTROL 结构体变量个数
  mxlc.pamxctrl = &mxc;        // MIXERCONTROL 结构体变量指针
  mxlc.cbmxctrl = sizeof(mxc); // MIXERCONTROL 结构体变量字节大小

  // 取得控制器信息
  rc = mixerGetLineControls((HMIXEROBJ)hMixer,
   &mxlc,
   MIXER_GETLINECONTROLSF_ONEBYTYPE);

  // 取得控制器信息成功的话,则
  if (MMSYSERR_NOERROR == rc)
  {
   // 获取控制器中的值的音量范围:mxc.Bounds.lMinimum到mxc.Bounds.lMaximum.
   MIXERCONTROLDETAILS        mxcd;      // 控制器的状态信息
   MIXERCONTROLDETAILS_SIGNED volStruct; // 音量结构体变量(就一个成员量)

   // MIXERCONTROLDETAILS 结构体变量清零
   ZeroMemory(&mxcd, sizeof(mxcd));

   mxcd.cbStruct = sizeof(mxcd);       // 微软用此办法判断版本
   mxcd.dwControlID = mxc.dwControlID; // 上面取得的控制器标识
   mxcd.paDetails = &volStruct;        // 音量结构体变量指针
   mxcd.cbDetails = sizeof(volStruct); // 音量结构体变量字节大小
   mxcd.cChannels = 1;                 // 取得或设置全部通道

   //  获取控制器中的值的音量范围:mxc.Bounds.lMinimum到mxc.Bounds.lMaximum. 

   // 获得音量值
   rc = mixerGetControlDetails((HMIXEROBJ)hMixer,
    &mxcd,
    MIXER_GETCONTROLDETAILSF_VALUE);

   if (MMSYSERR_NOERROR == rc)
   {
    long step = ( mxc.Bounds.lMaximum - mxc.Bounds.lMinimum ) /100;

    int index = ( volStruct.lValue - mxc.Bounds.lMinimum) /step ;
    printf("音量:%X", volStruct.lValue);
    CString str;
	str.Format("%d",volStruct.lValue);
   m_s = str;
   UpdateData(FALSE);
   str = "";
 
    return index;
   }
  }
 }

 return -1;
 CMixer mix;
 unsigned m;

 /*m = mix.GetVolume();
  CString str;
  str.Format("%d",m);
  m_s = str;
  UpdateData(FALSE);
  MessageBox(str);*/



}
不要做咸鱼 2014-06-04
  • 打赏
  • 举报
回复
友情帮顶 额不会啊楼主
赵4老师 2014-06-04
  • 打赏
  • 举报
回复
mixerGetControlDetails The mixerGetControlDetails function retrieves details about a single control associated with an audio line. MMRESULT mixerGetControlDetails( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails ); Parameters hmxobj Handle of the mixer device object being queried. pmxcd Address of a MIXERCONTROLDETAILS structure, which is filled with state information about the control. fdwDetails Flags for retrieving control details. The following values are defined: MIXER_GETCONTROLDETAILSF_LISTTEXT The paDetails member of the MIXERCONTROLDETAILS structure points to one or more MIXERCONTROLDETAILS_LISTTEXT structures to receive text labels for multiple-item controls. An application must get all list text items for a multiple-item control at once. This flag cannot be used with MIXERCONTROL_CONTROLTYPE_CUSTOM controls. MIXER_GETCONTROLDETAILSF_VALUE Current values for a control are retrieved. The paDetails member of the MIXERCONTROLDETAILS structure points to one or more details structures appropriate for the control class. MIXER_OBJECTF_AUX The hmxobj parameter is an auxiliary device identifier in the range of zero to one less than the number of devices returned by the auxGetNumDevs function. MIXER_OBJECTF_HMIDIIN The hmxobj parameter is the handle of a MIDI (Musical Instrument Digital Interface) input device. This handle must have been returned by the midiInOpen function. MIXER_OBJECTF_HMIDIOUT The hmxobj parameter is the handle of a MIDI output device. This handle must have been returned by the midiOutOpen function. MIXER_OBJECTF_HMIXER The hmxobj parameter is a mixer device handle returned by the mixerOpen function. This flag is optional. MIXER_OBJECTF_HWAVEIN The hmxobj parameter is a waveform-audio input handle returned by the waveInOpen function. MIXER_OBJECTF_HWAVEOUT The hmxobj parameter is a waveform-audio output handle returned by the waveOutOpen function. MIXER_OBJECTF_MIDIIN The hmxobj parameter is the identifier of a MIDI input device. This identifier must be in the range of zero to one less than the number of devices returned by the midiInGetNumDevs function. MIXER_OBJECTF_MIDIOUT The hmxobj parameter is the identifier of a MIDI output device. This identifier must be in the range of zero to one less than the number of devices returned by the midiOutGetNumDevs function. MIXER_OBJECTF_MIXER The hmxobj parameter is the identifier of a mixer device in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function. This flag is optional. MIXER_OBJECTF_WAVEIN The hmxobj parameter is the identifier of a waveform-audio input device in the range of zero to one less than the number of devices returned by the waveInGetNumDevs function. MIXER_OBJECTF_WAVEOUT The hmxobj parameter is the identifier of a waveform-audio output device in the range of zero to one less than the number of devices returned by the waveOutGetNumDevs function. Return Values Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following: Value Description MIXERR_INVALCONTROL The control reference is invalid. MMSYSERR_BADDEVICEID The hmxobj parameter specifies an invalid device identifier. MMSYSERR_INVALFLAG One or more flags are invalid. MMSYSERR_INVALHANDLE The hmxobj parameter specifies an invalid handle. MMSYSERR_INVALPARAM One or more parameters are invalid. MMSYSERR_NODRIVER No mixer device is available for the object specified by hmxobj. Remarks All members of the MIXERCONTROLDETAILS structure must be initialized before calling this function. QuickInfo Windows NT: Requires version 3.1 or later. Windows: Requires Windows 95 or later. Windows CE: Unsupported. Header: Declared in mmsystem.h. Import Library: Use winmm.lib. Unicode: Implemented as Unicode and ANSI versions on Windows NT. See Also Audio Mixers Overview, Audio Mixer Functions, MIXERCONTROLDETAILS, MIXERCONTROLDETAILS_LISTTEXT, auxGetNumDevs, midiInOpen, midiOutOpen, mixerOpen, waveInOpen, waveOutOpen, midiInGetNumDevs, midiOutGetNumDevs, mixerGetNumDevs, waveInGetNumDevs, waveOutGetNumDevs
  • 打赏
  • 举报
回复
我学习到了。
SuperCoderJz 2014-06-04
  • 打赏
  • 举报
回复
引用 8 楼 zhao4zhong1 的回复:
http://bbs.csdn.net/topics/390374955
好吧 还是调不出来 我才上大二 你说的我也看不懂 全英文的
赵4老师 2014-06-04
  • 打赏
  • 举报
回复
赵4老师 2014-06-04
  • 打赏
  • 举报
回复
以下节选自MSDN98\SAMPLES\VC98\SDK\GRAPHICS\AUDIO\MIXAPP\MAMETER.C ,仅供参考:
//--------------------------------------------------------------------------;
//
//  BOOL MixAppControlChangeMeter
//
//  Description:
//
//
//  Arguments:
//      HWND hwnd:
//
//      HMIXER hmx:
//
//      DWORD dwControlID:
//
//  Return (BOOL):
//
//  History:
//      09/22/93
//
//--------------------------------------------------------------------------;

BOOL FNLOCAL MixAppControlChangeMeter
(
    HWND                    hwnd,
    HMIXER                  hmx,
    DWORD                   dwControlID
)
{
    MMRESULT                        mmr;
    HWND                            htxt;
    PMACONTROLINSTANCE_METER        pmaci_meter;
    LPMACONTROLINSTANCE             pmaci;
    LPMIXERLINE                     pmxl;
    LPMIXERCONTROL                  pmxctrl;
    PMIXERCONTROLDETAILS_SIGNED     pmxcd_s;
    UINT                            cChannels;
    UINT                            cMultipleItems;
    UINT                            u;
    UINT                            uIndex;
    UINT                            v;
    MIXERCONTROLDETAILS             mxcd;
    HWND                            hsbFocus;
    HWND                            hsb;
    BOOL                            fSigned;
    DWORD                           dwRange;
    DWORD                           dwValue;
    int                             nValue;


    hsbFocus = GetFocus();
    if (NULL == hsbFocus)
    {
        hsbFocus = GetDlgItem(hwnd, IDD_MACONTROL_MULTICHANNEL_BASE);
    }
    else
    {
        uIndex = GetDlgCtrlID(hsbFocus);
        if (uIndex < IDD_MACONTROL_MULTICHANNEL_BASE)
        {
            hsbFocus = GetDlgItem(hwnd, IDD_MACONTROL_MULTICHANNEL_BASE);
        }
    }


    //
    //
    //
    pmaci_meter = (PMACONTROLINSTANCE_METER)(UINT)GetWindowLong(hwnd, DWL_USER);
    pmaci       = pmaci_meter->pmaci;
    pmxl        = pmaci->pmxl;
    pmxctrl     = pmaci->pmxctrl;
    pmxcd_s     = &pmaci_meter->pmxcd_s[0];
    fSigned     = pmaci_meter->fSigned;
    dwRange     = pmaci_meter->dwRange;

    cChannels = (UINT)pmxl->cChannels;
    if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl)
        cChannels = 1;

    //
    //
    //
    mxcd.cbStruct       = sizeof(mxcd);
    mxcd.dwControlID    = pmxctrl->dwControlID;
    mxcd.cChannels      = cChannels;
    mxcd.cMultipleItems = pmxctrl->cMultipleItems;
    mxcd.cbDetails      = sizeof(*pmxcd_s);
    mxcd.paDetails      = pmxcd_s;

    mmr = mixerGetControlDetails((HMIXEROBJ)pmaci->hmx, &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
    if (MMSYSERR_NOERROR != mmr)
    {
        AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
                  "mixerGetControlDetails(ctrlid=%.08lXh) failed on hmx=%.04Xh, mmr=%u!",
                  pmxctrl->dwControlID, pmaci->hmx, mmr);
        return (FALSE);
    }


    cMultipleItems = 1;
    if (MIXERCONTROL_CONTROLF_MULTIPLE & pmxctrl->fdwControl)
        cMultipleItems = (UINT)pmxctrl->cMultipleItems;


    for (u = 0; u < cChannels; u++)
    {
        for (v = 0; v < cMultipleItems; v++)
        {
            uIndex = (u * cMultipleItems) + v;

            if (fSigned)
            {
                dwValue = (DWORD)(pmxcd_s[uIndex].lValue -
                                  pmxctrl->Bounds.lMinimum);
            }
            else
            {
                dwValue  = (DWORD)pmxcd_s[uIndex].lValue;
                dwValue -= pmxctrl->Bounds.dwMinimum;
            }

            nValue = (int)MulDivRN(dwValue, 32767, dwRange);

            //
            //  Windows is stupid and forces an update to scrollbars
            //  (a flickering paint) even when the position does not
            //  change... so don't update if it is already in the
            //  right position.
            //
            hsb = GetDlgItem(hwnd, IDD_MACONTROL_MULTICHANNEL_BASE + uIndex);

            if (hsbFocus == hsb)
            {
                htxt = GetDlgItem(hwnd, IDD_MACONTROL_TXT_VALUE);
                if (fSigned)
                {
                    AppSetWindowText(htxt, "mapped=%d, lValue=%ld",
                                     nValue,
                                     pmxcd_s[uIndex].lValue);
                }
                else
                {
                    AppSetWindowText(htxt, "mapped=%d, dwValue=%lu",
                                     nValue,
                                     pmxcd_s[uIndex].lValue);
                }
            }

            if (32767 - nValue == GetScrollPos(hsb, SB_CTL))
                continue;

            //
            //  note that we _invert_ the position since a meter will
            //  increase approaching the top (opposite of scrollbar
            //  logic)
            //
            SetScrollPos(hsb, SB_CTL, 32767 - nValue, TRUE);
        }
    }




    //
    //
    //
    mxcd.cbStruct       = sizeof(mxcd);
    mxcd.dwControlID    = pmxctrl->dwControlID;
    mxcd.cChannels      = 1;
    mxcd.cMultipleItems = pmxctrl->cMultipleItems;
    mxcd.cbDetails      = sizeof(*pmxcd_s);
    mxcd.paDetails      = pmxcd_s;

    mmr = mixerGetControlDetails((HMIXEROBJ)pmaci->hmx, &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
    if (MMSYSERR_NOERROR != mmr)
    {
        AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
                  "mixerGetControlDetails(ctrlid=%.08lXh) failed on hmx=%.04Xh, mmr=%u!",
                  pmxctrl->dwControlID, pmaci->hmx, mmr);
        return (FALSE);
    }


    for (v = 0; v < cMultipleItems; v++)
    {
        uIndex = v;

        if (fSigned)
        {
            dwValue = (DWORD)(pmxcd_s[uIndex].lValue -
                              pmxctrl->Bounds.lMinimum);
        }
        else
        {
            dwValue  = (DWORD)pmxcd_s[uIndex].lValue;
            dwValue -= pmxctrl->Bounds.dwMinimum;
        }

        nValue = (int)MulDivRN(dwValue, 32767, dwRange);

        hsb = GetDlgItem(hwnd, IDD_MACONTROL_UNIFORM_BASE + uIndex);
        if (hsbFocus == hsb)
        {
            htxt = GetDlgItem(hwnd, IDD_MACONTROL_TXT_VALUE);
            if (fSigned)
            {
                AppSetWindowText(htxt, "mapped=%d, lValue=%ld",
                                 nValue,
                                 pmxcd_s[uIndex].lValue);
            }
            else
            {
                AppSetWindowText(htxt, "mapped=%d, dwValue=%lu",
                                 nValue,
                                 pmxcd_s[uIndex].lValue);
            }
        }

        if (32767 - nValue == GetScrollPos(hsb, SB_CTL))
            continue;

        //
        //  note that we _invert_ the position since a meter will
        //  increase approaching the top (opposite of scrollbar
        //  logic)
        //
        SetScrollPos(hsb, SB_CTL, 32767 - nValue, TRUE);
    }


    return (TRUE);
} // MixAppControlChangeMeter()
SuperCoderJz 2014-06-04
  • 打赏
  • 举报
回复
引用 5 楼 zhao4zhong1 的回复:
参考MSDN98\SAMPLES\VC98\SDK\GRAPHICS\AUDIO\MIXAPP\*.* ? 在Google上搜“mixerGetControlDetails” ?
关键是我看的代码没错啊 可还是获取不到 不知道为什么 一直都是65532
赵4老师 2014-06-04
  • 打赏
  • 举报
回复
参考MSDN98\SAMPLES\VC98\SDK\GRAPHICS\AUDIO\MIXAPP\*.* ? 在Google上搜“mixerGetControlDetails” ?
  • 打赏
  • 举报
回复
这个要用到DS编程。

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧