All of lore.kernel.org
 help / color / mirror / Atom feed
* HFP microphone implementation
@ 2012-07-19 12:18 NetJackBlog
  0 siblings, 0 replies; only message in thread
From: NetJackBlog @ 2012-07-19 12:18 UTC (permalink / raw)
  To: linux-bluetooth

Good Morning,

I'm Jack and I'm trying to develop a custom HFP (hand free side) for 
using my PC as a microphone during phone calls.
Please excuse my typing errors but English is not my native language.
Well, I searched the web and I found that a lot of work was done with 
ofono.
My intent is to use more standard software as possible, so I rearranged 
some code found on the internet that implement HFP speakers through 
bluez and alsa

This is the code:

****************************************************************************
#include "btinclude.h"

#include <alsa/asoundlib.h>

int set_class(unsigned int cls, int timeout)
{
     int id;
     int fh;
     bdaddr_t btaddr;
     char pszaddr[18];

     // get the device ID
     // passing in NULL instead of a bdaddr_t will
     // give the ID of the first bluetooth device
     if ((id = hci_get_route(NULL)) < 0)
         return -1;

     // convert the device ID into a 6 byte bluetooth address
     if (hci_devba(id, &btaddr) < 0)
         return -1;

     // convert the address into a zero terminated string
     if (ba2str(&btaddr, pszaddr) < 0)
         return -1;

     // open a file handle to the HCI
     if ((fh = hci_open_dev(id)) < 0)
         return -1;

     // set the class
     if (hci_write_class_of_dev(fh, cls, timeout) != 0)
     {
         perror("hci_write_class ");
         return -1;
     }

     // close the file handle
     hci_close_dev(fh);

     printf("set device %s to class: 0x%06x\n", pszaddr, cls);

     return 0;
}

/***********************************************************************/

// source adapted from:
// http://people.csail.mit.edu/albert/bluez-intro/x604.html and
// http://nohands.sourceforge.net/source.html (libhfp/hfp.cpp: SdpRegister)

int register_sdp(uint8_t channel)
{
     const char *service_name = "HSP service";
     const char *service_dsc = "HSP";
     const char *service_prov = "working times";

     uuid_t hs_uuid, ga_uuid;

     sdp_profile_desc_t desc;

     uuid_t root_uuid, l2cap_uuid, rfcomm_uuid;
     sdp_list_t *l2cap_list = 0,
                *rfcomm_list = 0,
                *root_list = 0,
                *proto_list = 0,
                *access_proto_list = 0;

     sdp_data_t *channel_d = 0;

     int err = 0;
     sdp_session_t *session = 0;

     sdp_record_t *record = sdp_record_alloc();

     // set the name, provider, and description
     sdp_set_info_attr(record, service_name, service_prov, service_dsc);

     // service class ID (HEADSET)
     sdp_uuid16_create(&hs_uuid, HEADSET_SVCLASS_ID);

     if (!(root_list = sdp_list_append(0, &hs_uuid)))
         return -1;

     sdp_uuid16_create(&ga_uuid, GENERIC_AUDIO_SVCLASS_ID);

     if (!(root_list = sdp_list_append(root_list, &ga_uuid)))
         return -1;

     if (sdp_set_service_classes(record, root_list) < 0)
         return -1;

     sdp_list_free(root_list, 0);
     root_list = 0;

     // make the service record publicly browsable
     sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);

     root_list = sdp_list_append(0, &root_uuid);
     sdp_set_browse_groups( record, root_list );

     // set l2cap information
     sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
     l2cap_list = sdp_list_append( 0, &l2cap_uuid );
     proto_list = sdp_list_append( 0, l2cap_list );

     // set rfcomm information
     sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
     channel_d = sdp_data_alloc(SDP_UINT8, &channel);
     rfcomm_list = sdp_list_append( 0, &rfcomm_uuid );

     sdp_list_append( rfcomm_list, channel_d );
     sdp_list_append( proto_list, rfcomm_list );

     // attach protocol information to service record
     access_proto_list = sdp_list_append( 0, proto_list );
     sdp_set_access_protos( record, access_proto_list );

     sdp_uuid16_create(&desc.uuid, HEADSET_PROFILE_ID);

     // set the version to 1.0
     desc.version = 0x0100;

     if (!(root_list = sdp_list_append(NULL, &desc)))
         return -1;

     if (sdp_set_profile_descs(record, root_list) < 0)
         return -1;

     // connect to the local SDP server and register the service record
     session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY );
     err = sdp_record_register(session, record, 0);

     // cleanup
     sdp_data_free( channel_d );
     sdp_list_free( l2cap_list, 0 );
     sdp_list_free( rfcomm_list, 0 );
     sdp_list_free( root_list, 0 );
     sdp_list_free( access_proto_list, 0 );

     return err;
}

/***********************************************************************/

int rfcomm_listen(uint8_t channel)
{
     int sock;                        // socket descriptor for local 
listener
     int client;                        // socket descriptor for remote 
client
     unsigned int len = sizeof(struct sockaddr_rc);

     struct sockaddr_rc remote;        // local rfcomm socket address
     struct sockaddr_rc local;        // remote rfcomm socket address
     char pszremote[18];

     // initialize a bluetooth socket
     sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

     local.rc_family = AF_BLUETOOTH;

     // TODO: change this to a local address if you know what
     // address to use
     local.rc_bdaddr = *BDADDR_ANY;
     local.rc_channel = channel;

     // bind the socket to a bluetooth device
     if (bind(sock, (struct sockaddr *)&local, sizeof(struct 
sockaddr_rc)) < 0)
         return -1;

     // set the listening queue length
     if (listen(sock, 1) < 0)
         return -1;

     printf("accepting connections on channel: %d\n", channel);

     // accept incoming connections; this is a blocking call
     client = accept(sock, (struct sockaddr *)&remote, &len);

     ba2str(&remote.rc_bdaddr, pszremote);

     printf("received connection from: %s\n", pszremote);

     // turn off blocking
     if (fcntl(client, F_SETFL, O_NONBLOCK) < 0)
         return -1;

     // return the client socket descriptor
     return client;
}

/***********************************************************************/

int sco_listen()
{
     int sock;
     int client;
     unsigned int len = sizeof(struct sockaddr_sco);
     char pszremote[18];

     struct sockaddr_sco local;
     struct sockaddr_sco remote;

     sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);

     local.sco_family = AF_BLUETOOTH;

     local.sco_bdaddr = *BDADDR_ANY;

     if (bind(sock, (struct sockaddr*)&local, sizeof(struct 
sockaddr_sco)) < 0)
         return -1;

     if (listen(sock, 1) < 0)
         return -1;

     client = accept(sock, (struct sockaddr*)&remote, &len);

     ba2str(&remote.sco_bdaddr, pszremote);

     printf("sco received connection from: %s\n", pszremote);

     // close the listener
     close(sock);

     return client;
}

/***********************************************************************/

int handle_connection(int rfcommsock, int scosock)
{
     char scobuffer[256];
     char rfcommbuffer[256];
     int len;

     struct snd_pcm_t *sndhandle;

     // open the default sound device
     if (snd_pcm_open((snd_pcm_t **)&sndhandle, "default", 
SND_PCM_STREAM_CAPTURE, 0) < 0)
     {
         perror("snd_pcm_open ");
         return -1;
     }

     // initialize the device to handle an 8khz, single channel,
     // little endian audio data stream
     if (snd_pcm_set_params((snd_pcm_t *)sndhandle, 
SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 1,
             8000, 0, 0) < 0)
     {
         perror("set_params ");
         return -1;
     }




//    while (1)
//    {
    int soundread = snd_pcm_readi((snd_pcm_t *)sndhandle, scobuffer, 128 
/ 2);
    printf("frame letti %d\n", soundread);
         // read from the SCO socket
         // it should constantly stream data
     len = send(scosock, scobuffer, 128, 0);
      printf ("postsend %d\n", scosock);
             fprintf (stdout, "sent %d len %d\n", len, 256);
             perror ("send ");

     if (len <= 0)
     {

       printf("brekkasend");
//      break;
     }

         // send the sound data to the sound
         // the sound device expects "frames".  since we have 16 bit, single
         // channel data, each 2 bytes is one "frame"
//        snd_pcm_readi((snd_pcm_t *)sndhandle, scobuffer, len / 2);

         // read from the RFCOMM socket
         // this socket has blocking turned off so it will never block,
         // even if no data is available
         len = recv(rfcommsock, rfcommbuffer, 256, 0);

         // EWOULDBLOCK indicates the socket would block if we had a
         // blocking socket.  we'll safely continue if we receive that
         // error.  treat all other errors as fatal
         if (len < 0 && errno != EWOULDBLOCK)
         {
             perror("rfcomm recv ");
       printf("mark");
//            break;
         }
         else if (len > 0)
         {
             // received a message; print it to the screen and
             // return ATOK to the remote device
             rfcommbuffer[len] = '\0';

             printf("rfcomm received: %s\n", rfcommbuffer);
             send(rfcommsock, "ATOK\r\n", 6, 0);

//        }

         // printf("loop\n");
     }



     // close the sound device
     snd_pcm_close((snd_pcm_t *)sndhandle);

     close(scosock);
     close(rfcommsock);

     printf("client disconnected\n");

     return 0;
}

/***********************************************************************/

unsigned int cls = 0x280404;
int timeout = 1000;
uint8_t channel = 3;

int main()
{
     int rfcommsock;
     int scosock;

     if (set_class(cls, timeout) < 0)
     {
         perror("set_class ");
     }

     if (register_sdp(channel) < 0)
     {
         perror("register_sdp ");
         return -1;
     }

     if ((rfcommsock = rfcomm_listen(channel)) < 0)
     {
         perror("set_class ");
         return -1;
     }

     if ((scosock = sco_listen()) < 0)
     {
         perror("sco_listen ");
         return -1;
     }

     handle_connection(rfcommsock, scosock);

     return 0;
}

************************************************************


As you can see I had to comment the "while" statement in the 
"handle_connection" function to get things done.
It' s very strange to my unexpert eye, because that "while" must be 
uncommented to get the audio stream flow to the socket, but with the 
"while" the software doesn't works and tells me "send: Resource 
temporarily unavaible". With the "while" If I start the software, answer 
a call and quit with "ctrl-c" the connection start working and I can use 
my pc mic as phone mic. When I saw this I decided to comment the "while" 
so that the software can quit itself.
Can someone explain this? I would like to figure out what is going wrong 
so I can correct the code.

I tested the software on ubuntu 12.04; kernel 3.2.0-26; bluez 4.98;

Thanks for your patience and time, have a nice day,

Jack

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2012-07-19 12:18 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-19 12:18 HFP microphone implementation NetJackBlog

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.