欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

捕获电脑的声音放到手机播放

程序员文章站 2022-05-10 22:40:21
在pc上使用adb命令:adb forward tcp:4626 tcp:4883,在PC上建立4626端口通信数据将被重定向到手机端server的4883端口;然后初始化sock...

在pc上使用adb命令:adb forward tcp:4626 tcp:4883,在PC上建立4626端口通信数据将被重定向到手机端server的4883端口;然后初始化socket,连接到手机4626端口,进行socket通信。PC端代码如下:

 

[html] 
DWORD WINAPI usbThreadFunc(LPVOID threadNum) 

    int length;  
    CString temp; 
    if(!initAdb())//adb init 
    { 
        MessageBox(0, L"初始化手机出错!", L"提示", MB_OK); 
        return 0; 
    } 
    if(!InItClientSock())//socket init 
    { 
        MessageBox(0, L"初始化IP地址出错!", L"提示", MB_OK); 
        return 0; 
    } 
    if(!USBConnectSock((HWND)threadNum))//connect socket 
    { 
        MessageBox(0, L"连接IP地址出错!", L"提示", MB_OK); 
        return 0; 
    } 
    //等待连接的时候,连接可能被取消。 
    if(clientThreadRun) 
    { 
    } 
    else 
    { 
        MessageBox(0, L"用户取消!", L"提示", MB_OK); 
        return 0; 
    } 
    SetDlgItemText( (HWND)threadNum, IDC_SOUNDFILE, TEXT("&USB Disconnect") ); 
    EnableWindow( GetDlgItem( (HWND)threadNum, IDC_RECORD ), TRUE ); 
    EnableWindow( GetDlgItem( (HWND)threadNum, IDC_BUTTON_WIFI ), FALSE );   
    while(clientThreadRun) 
    { 
        if( (length = recv(clientSock,(char*)recv_message_client,sizeof(recv_message_client),0))>0) 
        { 
            memset(recv_message_client, 0, sizeof(recv_message_client)); 
            LogPrintf(recv_message_client); 
        }        
    } 
    return 0; 

DWORD WINAPI usbThreadFunc(LPVOID threadNum)
{
 int length; 
 CString temp;
 if(!initAdb())//adb init
 {
  MessageBox(0, L"初始化手机出错!", L"提示", MB_OK);
  return 0;
 }
 if(!InItClientSock())//socket init
 {
  MessageBox(0, L"初始化IP地址出错!", L"提示", MB_OK);
  return 0;
 }
 if(!USBConnectSock((HWND)threadNum))//connect socket
 {
  MessageBox(0, L"连接IP地址出错!", L"提示", MB_OK);
  return 0;
 }
 //等待连接的时候,连接可能被取消。
 if(clientThreadRun)
 {
 }
 else
 {
  MessageBox(0, L"用户取消!", L"提示", MB_OK);
  return 0;
 }
 SetDlgItemText( (HWND)threadNum, IDC_SOUNDFILE, TEXT("&USB Disconnect") );
 EnableWindow( GetDlgItem( (HWND)threadNum, IDC_RECORD ), TRUE );
 EnableWindow( GetDlgItem( (HWND)threadNum, IDC_BUTTON_WIFI ), FALSE ); 
 while(clientThreadRun)
 {
  if( (length = recv(clientSock,(char*)recv_message_client,sizeof(recv_message_client),0))>0)
  {
   memset(recv_message_client, 0, sizeof(recv_message_client));
   LogPrintf(recv_message_client);
  }  
 }
 return 0;
}

这里说道最重要的是捕获声音,下面的代码启动了一个线程来处理捕获到的声音:


[html] 
DWORD WINAPI captureThreadFunc(LPVOID hDlg) 

    DWORD dwResult; 
    while(g_bRecording)  
    {  
        dwResult = MsgWaitForMultipleObjects( 1, &g_hNotificationEvent, FALSE, INFINITE, QS_ALLEVENTS ); 
        switch( dwResult ) 
        { 
        case STATUS_WAIT_0://case WAIT_OBJECT_0 + 0: 
 
            RecordCapturedData(); 
            break; 
        } 
    } 
    return 0; 

DWORD WINAPI captureThreadFunc(LPVOID hDlg)
{
 DWORD dwResult;
 while(g_bRecording)
 {
  dwResult = MsgWaitForMultipleObjects( 1, &g_hNotificationEvent, FALSE, INFINITE, QS_ALLEVENTS );
  switch( dwResult )
  {
  case STATUS_WAIT_0://case WAIT_OBJECT_0 + 0:

   RecordCapturedData();
   break;
  }
 }
 return 0;
}

在创建捕获声音的设备的时候,会创建一个事件,这个事件就是捕获到一定长度的声音之后(比如2K大小的声音),会发出一个通知,告诉你去处理。上面的线程,就是一直待等待这个事件,然后再去处理捕获到的声音,把声音发送给socket,交给手机处理,代码:


[html] 
HRESULT RecordCapturedData()  

    HRESULT hr; 
    VOID*   pbCaptureData    = NULL; 
    DWORD   dwCaptureLength; 
    VOID*   pbCaptureData2   = NULL; 
    DWORD   dwCaptureLength2; 
    DWORD   dwReadPos; 
    DWORD   dwCapturePos; 
    LONG lLockSize; 
 
    if( NULL == g_pDSBCapture ) 
        return S_FALSE; 
 
    if( FAILED( hr = g_pDSBCapture->GetCurrentPosition( &dwCapturePos, &dwReadPos ) ) ) 
        return DXTRACE_ERR_MSGBOX( TEXT("GetCurrentPosition"), hr ); 
 
    lLockSize = dwReadPos - g_dwNextCaptureOffset; 
    if( lLockSize < 0 ) 
        lLockSize += g_dwCaptureBufferSize; 
 
    // Block align lock size so that we are always write on a boundary 
    lLockSize -= (lLockSize % g_dwNotifySize); 
 
    if( lLockSize == 0 ) 
        return S_FALSE; 
 
    // Lock the capture buffer down 
    if( FAILED( hr = g_pDSBCapture->Lock( g_dwNextCaptureOffset, lLockSize,  
                                          &pbCaptureData, &dwCaptureLength,  
                                          &pbCaptureData2, &dwCaptureLength2, 0L ) ) ) 
        return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr ); 
 
     
    // Write the data to socket发送给手机 
    socketSend(pbCaptureData,dwCaptureLength); 
    // Move the capture offset along 
    g_dwNextCaptureOffset += dwCaptureLength;  
    g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer 
 
    if( pbCaptureData2 != NULL ) 
    { 
        // Write the data to socket发送给手机 
        socketSend(pbCaptureData2,dwCaptureLength2); 
 
        // Move the capture offset along 
        g_dwNextCaptureOffset += dwCaptureLength2;  
        g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer 
    } 
 
    // Unlock the capture buffer 
    g_pDSBCapture->Unlock( pbCaptureData,  dwCaptureLength,  
                           pbCaptureData2, dwCaptureLength2 ); 
    return S_OK; 

HRESULT RecordCapturedData()
{
    HRESULT hr;
    VOID*   pbCaptureData    = NULL;
    DWORD   dwCaptureLength;
    VOID*   pbCaptureData2   = NULL;
    DWORD   dwCaptureLength2;
    DWORD   dwReadPos;
    DWORD   dwCapturePos;
    LONG lLockSize;

    if( NULL == g_pDSBCapture )
        return S_FALSE;

    if( FAILED( hr = g_pDSBCapture->GetCurrentPosition( &dwCapturePos, &dwReadPos ) ) )
        return DXTRACE_ERR_MSGBOX( TEXT("GetCurrentPosition"), hr );

    lLockSize = dwReadPos - g_dwNextCaptureOffset;
    if( lLockSize < 0 )
        lLockSize += g_dwCaptureBufferSize;

    // Block align lock size so that we are always write on a boundary
    lLockSize -= (lLockSize % g_dwNotifySize);

    if( lLockSize == 0 )
        return S_FALSE;

    // Lock the capture buffer down
    if( FAILED( hr = g_pDSBCapture->Lock( g_dwNextCaptureOffset, lLockSize,
                                          &pbCaptureData, &dwCaptureLength,
                                          &pbCaptureData2, &dwCaptureLength2, 0L ) ) )
        return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );

 
    // Write the data to socket发送给手机
 socketSend(pbCaptureData,dwCaptureLength);
    // Move the capture offset along
    g_dwNextCaptureOffset += dwCaptureLength;
    g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer

    if( pbCaptureData2 != NULL )
    {
        // Write the data to socket发送给手机
   socketSend(pbCaptureData2,dwCaptureLength2);

        // Move the capture offset along
        g_dwNextCaptureOffset += dwCaptureLength2;
        g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer
    }

    // Unlock the capture buffer
    g_pDSBCapture->Unlock( pbCaptureData,  dwCaptureLength,
                           pbCaptureData2, dwCaptureLength2 );
    return S_OK;
}

通过socket发送数据的代码很简单,没有任何处理捕获到的声音数据,就发送给手机了

[html]
VOID socketSend(VOID* send_message, int length) 

    if(clientSockConnect==0) 
    {        
        int send_len = length; 
        char * buf = (char*)send_message; 
 
        while(send_len>0) 
        {        
            int rc = send(clientSock,buf,send_len, 0);//MSG_OOB 
            if (rc < 1)//if (rc == SOCKET_ERROR || rc == 0) 
            { 
                break; 
            }    
            send_len -= rc; 
            buf += rc; 
        } 
        buf = NULL; 
    } 

VOID socketSend(VOID* send_message, int length)
{
 if(clientSockConnect==0)
 {  
  int send_len = length;
  char * buf = (char*)send_message;

  while(send_len>0)
  {  
   int rc = send(clientSock,buf,send_len, 0);//MSG_OOB
   if (rc < 1)//if (rc == SOCKET_ERROR || rc == 0)
   {
    break;
   } 
   send_len -= rc;
   buf += rc;
  }
  buf = NULL;
 }
}
手机端的代码如下,注意手机上audioTrack的设置:44100,AudioFormat.CHANNEL_CONFIGURATION_STEREO,AudioFormat.ENCODING_PCM_16BIT。在启动电脑捕获声音的时候也要同样的设置,否则播放的声音是杂音:


[html] 
public class TcpConnect extends Thread { 
    private ServerSocket mServerSocket; 
    private Socket mClient; 
    private Handler mHandler; 
    private boolean running = false; 
    private boolean palying = false; 
 
    private int audioPlayBufSize; 
    private AudioTrack audioTrack; 
    private static final int frequency = 44100; 
    private static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO; 
    private static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; 
 
    private ArrayList<byte[]> inBuf = new ArrayList<byte[]>(); 
 
    public TcpConnect(Handler handler) { 
        mHandler = handler; 
 
        audioPlayBufSize = AudioTrack.getMinBufferSize(frequency, 
                channelConfiguration, audioEncoding); 
        audioTrack = new AudioTrack( 
                AudioManager.STREAM_MUSIC,// .STREAM_RING,//.STREAM_MUSIC, 
                frequency, channelConfiguration, audioEncoding, 
                audioPlayBufSize, AudioTrack.MODE_STREAM); 
        audioTrack.setStereoVolume(1.0f, 1.0f); 
        Log.d("playPCAudio", "audioPlayBufSize: " + audioPlayBufSize); 
 
        palying = false; 
        inBuf.clear(); 
    } 
 
    public void run() { 
        try { 
            mServerSocket = new ServerSocket(4883); 
 
            System.out.println("TcpConnect" + "开始监听"); 
            mClient = mServerSocket.accept(); 
            System.out.println("TcpConnect" + "检测到有连接"); 
            InputStream is = mClient.getInputStream(); 
 
            running = true; 
            int readLen = 0; 
            byte[] readBuf = new byte[audioPlayBufSize]; 
 
            System.out.println("TcpConnect" + "接收"); 
            playThread palyt = new playThread(); 
            palyt.setPriority(Thread.MAX_PRIORITY); 
            palyt.start(); 
 
            while (running) { 
                if ((readLen = is.read(readBuf, 0, audioPlayBufSize)) > 0) { 
                    byte[] tmpBuf = new byte[readLen]; 
                    System.arraycopy(readBuf, 0, tmpBuf, 0, readLen); 
                    synchronized (inBuf) { 
                        inBuf.add(tmpBuf); 
                    } 
                } 
            } 
        } catch (Exception e) { 
            System.out.println("TcpConnect TCP error:" + e.getMessage()); 
        } 
        System.out.println("TcpConnect over"); 
    } 
 
    class playThread extends Thread { 
 
        public playThread() { 
        } 
        public void run() { 
            audioTrack.play(); 
            palying = true; 
 
            while (running) { 
                ArrayList<byte[]> buf = new ArrayList<byte[]>(); 
                buf.clear(); 
                synchronized (inBuf) { 
                    if (inBuf.size() == 0) 
                        continue; 
                    buf = (ArrayList<byte[]>) inBuf.clone(); 
                    inBuf.clear(); 
                } 
                for (int i = 0; i < buf.size(); i++) { 
                    byte[] tmpBuf = buf.get(i); 
                    audioTrack.write(tmpBuf, 0, tmpBuf.length); 
                } 
            } 
            if (palying) { 
                audioTrack.stop(); 
                audioTrack.release(); 
                palying = false; 
            } 
        } 
    }