纯win32实现录音器并播放功能

24 篇文章 1 订阅
23 篇文章 1 订阅

http://blog.sina.com.cn/s/blog_149e9d2ec0102wyz9.html

首先大家看截图:

纯win32实现录音器并播放功能

这个是最近我花了将近两天的时间写的一个录音器,之前完全0基础。做完后收货很大,现在打算把代码贴出来供大家学习,欢迎大家指导,另外我在我的博客中还有两套用C语言写的录音器,那个更加容易理解,欢迎大家查看。
把我的代码直接粘贴,复制即可使用。
这里主要是demoWin.cpp文件代码:
// demoWin.cpp : Defines the entry point for theapplication.
//


#include "stdafx.h"
#include "demoWin.h"
#include <windows.h>
#include
#include
#include "mmsystem.h"

#pragma comment(lib, "winmm.lib")

#define MAX_LOADSTRING 100
#define BLOCK 1024 //定义块的大小


// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window classname
HWND g_hWndStartRecord;                             //开始录音按钮句柄
HWND g_hWndStatic; //界面显示时间信息
HWND g_hWndStopRecord;                               //停止录音按钮句柄
HWND g_hWndStartPlay;                               //开始播放录音按钮句柄
HWND g_hWndPausePlay; //暂停播放录音按钮句柄
HWND g_hWndStopPlay;                                 //停止播放录音按钮句柄

//录音机相关全局变量
FILE *fp = NULL;
HWAVEIN phwi;
char g_fileName[] = "MyRecord.wav";

//win32和录音机相关的全局变量
BOOL bFlag = TRUE;
BOOL bPlay = FALSE;

// Forward declarations of functions included in this codemodule:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
BOOL SetStartRecoron(HWND hWnd, LPARAM lParam);//设置开始录音按钮
BOOL SetStopRecoron(HWND hWnd, LPARAM lParam);//设置停止录音按钮
BOOL SetTimeInfo(HWND hWnd, LPARAM lParam); //设置时间显示到界面
BOOL SetStartPlayButton(HWND hWnd, LPARAM lParam);//设置播放录音按钮
BOOL SetPausePlayButton(HWND hWnd, LPARAM lParam);//设置暂停播放录音按钮
BOOL SetStopPlayButton(HWND hWnd, LPARAM lParam);//设置停止播放录音按钮
BOOL ShowInfo(HWND hWnd, LPARAM lParam); //显示提示信息
VOID CALLBACK DelayOneSecondProc(HWND hwnd, UINT message, UINTidTimer, DWORD dwTime); //延时一秒

//录音机相关函数
BOOL getNumDrive();
BOOL getDevCaps();
VOID writeFormat(WAVEFORMATEX );
BOOL openDrive();
VOID run_test();
DWORD CALLBACK MicCallback(HWAVEIN hwavein, UINT uMsg, DWORDdwInstance, DWORD dwParam1, DWORD dwParam2);
BOOL recordWave();
BOOL openFile();
VOID closeDrive();
VOID closeFile();


//win32和录音机相关的函数
DWORD WINAPI threadPro(LPVOID lpParam);


int APIENTRY _tWinMain(HINSTANCE hInstance,
                      HINSTANCE hPrevInstance,
                      LPTSTR     lpCmdLine,
                      int       nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

  // TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
unsigned int count = 0;

// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle,MAX_LOADSTRING);
LoadString(hInstance, IDC_DEMOWIN, szWindowClass,MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

hAccelTable = LoadAccelerators(hInstance,MAKEINTRESOURCE(IDC_DEMOWIN));

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}



//
//   FUNCTION: MyRegisterClass()
//
//   PURPOSE: Registers the windowclass.
//
//   COMMENTS:
//
//     This function and itsusage are only necessary if you want this code
//     to be compatible withWin32 systems prior to the 'RegisterClassEx'
//     function that wasadded to Windows 95. It is important to call this function
//     so that theapplication will get 'well formed' small icons associated
//     with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_DEMOWIN));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+2);
wcex.lpszMenuName = NULL;//MAKEINTRESOURCE(IDC_DEMOWIN);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance,MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE,int)
//
//   PURPOSE: Saves instance handle andcreates main window
//
//   COMMENTS:
//
//         In this function, we save the instance handle ina global variable and
//         create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;

    hInst = hInstance; //Store instance handle in our global variable

    hWnd =CreateWindow(szWindowClass, szTitle, WS_SYSMENU |WS_MINIMIZEBOX,//WS_OVERLAPPEDWINDOW
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance,NULL);

    if (!hWnd)
    {
      return FALSE;
    }

    MoveWindow(hWnd, 700,450, 300, 120, FALSE);
    ShowWindow(hWnd,nCmdShow);
    UpdateWindow(hWnd);

    return TRUE;
}

//
//   FUNCTION: WndProc(HWND, UINT, WPARAM,LPARAM)
//
//   PURPOSE:   Processesmessages for the main window.
//
//   WM_COMMAND - process the applicationmenu
//   WM_PAINT - Paint the main window
//   WM_DESTROY - post a quit message andreturn
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAMwParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
DWORD threadId = -1;
HANDLE hThread;
HDC hdcStatic;
int iIdEvent = 10;

switch (message)
{
case WM_CREATE:
SetStartRecoron(hWnd, lParam);
SetTimeInfo(hWnd, lParam);
SetStopRecoron(hWnd, lParam);

SetStartPlayButton(hWnd, lParam);
SetPausePlayButton(hWnd, lParam);
SetStopPlayButton(hWnd, lParam);

//ShowInfo(hWnd, lParam);

EnableWindow(g_hWndStopRecord, FALSE);
EnableWindow(g_hWndStartPlay, FALSE);
EnableWindow(g_hWndPausePlay, FALSE);
EnableWindow(g_hWndStopPlay, FALSE);
break;
case WM_COMMAND:
wmId     =LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDC_BUTTON_STARTRECORD:
//MessageBox(NULL, L"测试开始录音", L"success", MB_OK);
//第一个参数为指向窗口的句柄,第二个参数为定时器ID,第三个参数为延时长度,第四个参数为定时函数
SetTimer(hWnd, iIdEvent, 1000, DelayOneSecondProc);

hThread = CreateThread(NULL, 0, threadPro, NULL, 0,&threadId);//打开线程,往后可以使用beginThread代替该函数
EnableWindow(g_hWndStopRecord, TRUE);
//run_test();
//while(bFlag);
break;
case IDC_BUTTON_STOPRECORD:
//MessageBox(NULL, L"测试停止录音", L"success", MB_OK);
KillTimer(hWnd, iIdEvent);
closeDrive();
bFlag = FALSE;
Sleep(100);
closeFile();
//ExitThread(threadId);//关闭线程

EnableWindow(g_hWndStartRecord, FALSE);
EnableWindow(g_hWndStopRecord, FALSE);
EnableWindow(g_hWndStartPlay, TRUE);

break;
case IDC_BUTTON_STARTPLAY:
//MessageBox(NULL, L"测试播放录音", L"success", MB_OK);
mciSendString(L"close mySound", NULL, 0, NULL);
char cSavePath[MAX_PATH];
memset(cSavePath, 0, sizeof(cSavePath));
sprintf(cSavePath, "open MyRecord.wav alias mySound",g_fileName);
mciSendStringA( cSavePath, NULL, 0, NULL);
mciSendString(L"play mySound", NULL, 0, NULL);

EnableWindow(g_hWndPausePlay, TRUE);
EnableWindow(g_hWndStopPlay, TRUE);
break;
case IDC_BUTTON_PAUSEPLAY:
//MessageBox(NULL, L"测试暂停播放录音", L"success", MB_OK);
if (!bPlay)
{
mciSendString(L"pause mySound", NULL, 0, NULL);
bPlay = TRUE;
SetWindowText(g_hWndPausePlay, L"继续播放");
//MessageBox(NULL, L"测试暂停播放录音", L"success", MB_OK);
}
else
{
mciSendString(L"resume mySound", NULL, 0, NULL);
bPlay = FALSE;
SetWindowText(g_hWndPausePlay, L"暂停播放");
//MessageBox(NULL, L"测试继续播放录音", L"success", MB_OK);
}
EnableWindow(g_hWndStartPlay, TRUE);
EnableWindow(g_hWndStopPlay, TRUE);
break;
case IDC_BUTTON_STOPPLAY:
//MessageBox(NULL, L"测试停止播放录音", L"success", MB_OK);
mciSendString(L"stop mySound", NULL, 0, NULL);
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd,About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
caseWM_CTLCOLORSTATIC://设置static的颜色,另外edit,button,listBox等文本也可以通过这样的方式设置
hdcStatic = (HDC)wParam;
SetBkMode(hdcStatic, TRANSPARENT);//设置static的颜色为透明,即背景透明
SetBkColor(hdcStatic, RGB(0x41, 0x96,0x4f));//设置控件中文本的颜色
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

DWORD WINAPI threadPro(LPVOID lpParam)
{
run_test();
while(bFlag);
return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam,LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;

case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) ==IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}

//设置开始录音按钮
BOOL SetStartRecoron(HWND hWnd, LPARAM lParam)
{
g_hWndStartRecord = CreateWindow(L"button",
L"开始录音",
WS_CHILD | WS_VISIBLE,
20, 10, 70, 20,
hWnd, (HMENU)IDC_BUTTON_STARTRECORD,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
if (NULL == g_hWndStartRecord)
{
return FALSE;
}
return TRUE;
}

//设置停止录音按钮
BOOL SetStopRecoron(HWND hWnd, LPARAM lParam)
{
g_hWndStopRecord = CreateWindow(L"button",
L"停止录音",
WS_CHILD | WS_VISIBLE,
200, 10, 70, 20,
hWnd, (HMENU)IDC_BUTTON_STOPRECORD,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
if (NULL == g_hWndStopRecord)
{
return FALSE;
}
return TRUE;
}

//界面上显示时间
BOOL SetTimeInfo(HWND hWnd, LPARAM lParam)
{
g_hWndStatic = CreateWindowW(L"static",
L"1",
WS_CHILD | WS_VISIBLE | SS_CENTER,
100, 10, 40, 20,
hWnd, (HMENU)1,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
if (NULL == g_hWndStatic)
{
return FALSE;
}
return TRUE;
}

//设置播放录音按钮
BOOL SetStartPlayButton(HWND hWnd, LPARAM lParam)
{
g_hWndStartPlay = CreateWindow(L"button",
L"播放",
WS_CHILD | WS_VISIBLE | SS_CENTER,
20, 50, 70, 20,
hWnd, (HMENU)IDC_BUTTON_STARTPLAY,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
if (NULL == g_hWndStartPlay)
{
return FALSE;
}
return TRUE;
}

//设置暂停播放录音按钮
BOOL SetPausePlayButton(HWND hWnd, LPARAM lParam)
{
g_hWndPausePlay = CreateWindow(L"button",
L"暂停播放",
WS_CHILD | WS_VISIBLE | SS_CENTER,
110, 50, 70, 20,
hWnd, (HMENU)IDC_BUTTON_PAUSEPLAY,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
if (NULL == g_hWndPausePlay)
{
return FALSE;
}
return TRUE;
}

//设置停止播放录音按钮
BOOL SetStopPlayButton(HWND hWnd, LPARAM lParam)
{
g_hWndStopPlay = CreateWindow(L"button",
L"停止播放",
WS_CHILD | WS_VISIBLE | SS_CENTER,
200, 50, 70, 20,
hWnd, (HMENU)IDC_BUTTON_STOPPLAY,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
if (NULL == g_hWndStopPlay)
{
return FALSE;
}
return TRUE;
}

//界面上显示提示信息
BOOL ShowInfo(HWND hWnd, LPARAM lParam)
{
HWND hWndStatic;
hWndStatic = CreateWindowW(L"static",
L"友情提示:\n由于时间紧促,这个程序完成了一个大概的功能,存在些许bug,我在此处先罗列出来方便使用学习。\n"
L"1. 请先点击“录音”按钮,然后才可点击停止录音按钮。\n "
L"2. 在完成录音后,请先点击“播放”按钮试听刚刚录音,然后才可以点击“暂停”按钮,或者“停止”按钮.",
WS_CHILD | WS_VISIBLE ,
8, 80, 280, 150,
hWnd, (HMENU)1,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
if (NULL == hWndStatic)
{
return FALSE;
}

return TRUE;
}

VOID CALLBACK DelayOneSecondProc(HWND hwnd, UINT message, UINTidTimer, DWORD dwTime)
{
static unsigned int count = 2;
SetWindowText(g_hWndStatic, L"");
char tCount[16];
memset(tCount, 0, sizeof tCount);
sprintf(tCount, "%d", count++);
SetWindowTextA(g_hWndStatic, tCount);
}


BOOL getNumDrive()//音频数量
{
return waveInGetNumDevs() < 1 ? FALSE : TRUE;//1  音频输入数量
}

BOOL getDevCaps()
{
WAVEINCAPS waveIncaps;
MMRESULT mmResult =waveInGetDevCaps(0,&waveIncaps,sizeof(WAVEINCAPS));//2设备描述
if (MMSYSERR_NOERROR != mmResult)
{
return FALSE;
}
return TRUE;
}



//写成wav格式
void writeFormat(WAVEFORMATEX waveFormat)
{
fwrite("RIFF", 1, 4, fp);
unsigned int dwDataLength = BLOCK * BLOCK;
unsigned int waveFormatSize = sizeof WAVEFORMATEX;
unsigned int Sec = (dwDataLength + waveFormatSize);
fwrite(&Sec,sizeof(Sec), 1, fp);
fwrite("WAVE",4, 1, fp);
fwrite("fmt ", 1, 4, fp);
fwrite(&waveFormatSize, sizeof(waveFormatSize), 1,fp);
fwrite(&waveFormat.wFormatTag,sizeof(waveFormat.wFormatTag), 1,fp);
fwrite(&waveFormat.nChannels,sizeof(waveFormat.nChannels),1, fp);
fwrite(&waveFormat.nSamplesPerSec,sizeof(waveFormat.nSamplesPerSec),1, fp);
fwrite(&waveFormat.nAvgBytesPerSec,sizeof(waveFormat.nAvgBytesPerSec),1, fp);
fwrite(&waveFormat.nBlockAlign,sizeof(waveFormat.nBlockAlign),1, fp);
fwrite(&waveFormat.wBitsPerSample,sizeof(waveFormat.wBitsPerSample),1, fp);
fwrite(&waveFormat.cbSize,sizeof(waveFormat.cbSize), 1,fp);
fwrite("data",4, 1, fp);
fwrite(&dwDataLength,sizeof(dwDataLength), 1, fp);
}

BOOL openDrive(WAVEFORMATEX *pwfx)
{
MMRESULTmmResult=waveInOpen(&phwi,WAVE_MAPPER,pwfx,(DWORD)(MicCallback),NULL,CALLBACK_FUNCTION);//3
if (MMSYSERR_NOERROR != mmResult)
{
return FALSE;
}
return TRUE;
}

DWORD CALLBACK MicCallback(HWAVEIN hwavein, UINT uMsg, DWORDdwInstance, DWORD dwParam1, DWORD dwParam2)
{
switch(uMsg) 
{
case WIM_OPEN:
//设备已经打开...
break;

case WIM_DATA:
{
WAVEHDR *pWaveHdr = (WAVEHDR*)dwParam1;
waveInPrepareHeader(hwavein, pWaveHdr, sizeof WAVEHDR);
waveInAddBuffer(hwavein, pWaveHdr, sizeof(WAVEHDR));
pWaveHdr->lpData;
int a = pWaveHdr->dwBufferLength;
int writed = 0;
writed = fwrite(pWaveHdr->lpData , 1, 10240, fp);
}

break;
case WIM_CLOSE:
//设备已经关闭...
break;
default:
break;
}
return 0;
}

BOOL openFile()
{
fp = fopen(g_fileName, "wb");
if (NULL == fp)
{
return FALSE;
}
return TRUE;
}

VOID run_test()
{
if (FALSE == openFile())
{
return;
}

if (FALSE == getNumDrive())
{
return;
}

if (FALSE == getDevCaps())
{
return;
}

WAVEFORMATEX pwfx ={WAVE_FORMAT_PCM,// wFormatTag,格式标志
2, // nChannels,通道数,单声道数据用单通道,立体声通道用双通道
44100, // nSamplesPerSec,采样率(HZ),每秒钟采取样本的次数
10240, // nAvgBytesPerSec,每秒转换数据的字节数,forWAVE_FORMAT_PCM,nAvgBytesPerSec = nSamplesPerSec *nBlockAlign。此处的大小与waveInOopen回调函数中写入数据的大小应该一直,否则会出现问题
4, // nBlockAlign,每个样本的字节数,for WAVE_FORMAT_PCM,nBlockAlign =(nChannels × wBitsPerSample) / 8
16, // wBitsPerSample,每个样本的位数,forWAVE_FORMAT_PCM,wBitsPerSample必须等于8或者16
0 // cbSize,附加在该结构体后面的格式信息的大小
};

writeFormat(pwfx);

MMRESULTmmResult=waveInOpen(&phwi,WAVE_MAPPER,&pwfx,(DWORD)(MicCallback),NULL,CALLBACK_FUNCTION);//3
if (MMSYSERR_NOERROR != mmResult)
{
return;
}

WAVEHDR pwh1;
char buffer1[10240];
pwh1.lpData=buffer1;
pwh1.dwBufferLength=10240;
pwh1.dwUser=1;
pwh1.dwFlags=0;
mmResult=waveInPrepareHeader(phwi,&pwh1,sizeof(WAVEHDR));//4  准备缓冲区1

WAVEHDR pwh2;
char buffer2[10240];
pwh2.lpData=buffer2;
pwh2.dwBufferLength=10240;
pwh2.dwUser=2;
pwh2.dwFlags=0;
mmResult=waveInPrepareHeader(phwi,&pwh2,sizeof(WAVEHDR));//4  准备缓冲区2

if(MMSYSERR_NOERROR==mmResult)
{
mmResult=waveInAddBuffer(phwi,&pwh1,sizeof(WAVEHDR));//5  将缓冲区1加入音频输入设备
mmResult=waveInAddBuffer(phwi,&pwh2,sizeof(WAVEHDR));//5  将缓冲区2加入音频输入设备

if(MMSYSERR_NOERROR==mmResult)
{
mmResult=waveInStart(phwi);//6     请求开始录音
}
}
}

void closeFile()
{
//关闭文件
fclose(fp);
}

void closeDrive()
{
//停止设备
if (MMSYSERR_NOERROR != waveInStop(phwi))
{
MessageBox(NULL, L"停止设备!", L"success", MB_OK);
}
//关闭设备
if (MMSYSERR_NOERROR != waveInClose(phwi))
{
MessageBox(NULL, L"关闭设备!", L"success", MB_OK);
}

}


这里是Resource.h文件里面只需要填加如下几行,添加行已加粗。
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by demoWin.rc
//

#define IDS_APP_TITLE 103

#define IDR_MAINFRAME 128
#define IDD_DEMOWIN_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDI_DEMOWIN 107
#define IDI_SMALL 108
#define IDC_DEMOWIN 109

#define IDC_BUTTON_STARTRECORD 111
#define IDC_BUTTON_STOPRECORD 112
#define IDC_BUTTON_STARTPLAY 113
#define IDC_BUTTON_PAUSEPLAY 114
#define IDC_BUTTON_STOPPLAY 115

#define IDC_MYICON 2
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS

#define _APS_NO_MFC 130
#define _APS_NEXT_RESOURCE_VALUE 129
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值