Can't compile the following code in C++ with Visual Studio 2017 (Got it from: Source Code):
#include <Wincodec.h> // we use WIC for saving images
#include <d3d9.h> // DirectX 9 header
#pragma comment(lib, "d3d9.lib") // link to DirectX 9 library
#include <stdio.h>
#include <Windows.h>
#include <wchar.h>
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)
#define HRCHECK(__expr) {hr=(__expr);if(FAILED(hr)){wprintf(L"FAILURE 0x%08X (%i)\n\tline: %u file: '%s'\n\texpr: '" WIDEN(#__expr) L"'\n",hr, hr, __LINE__,__WFILE__);goto cleanup;}}
#define RELEASE(__p) {if(__p!=nullptr){__p->Release();__p=nullptr;}}
HRESULT SavePixelsToFile32bppPBGRA(UINT width, UINT height, UINT stride, LPBYTE pixels, LPWSTR filePath, const GUID &format)
{
if (!filePath || !pixels)
return E_INVALIDARG;
HRESULT hr = S_OK;
IWICImagingFactory *factory = nullptr;
IWICBitmapEncoder *encoder = nullptr;
IWICBitmapFrameEncode *frame = nullptr;
IWICStream *stream = nullptr;
GUID pf = GUID_WICPixelFormat32bppPBGRA;
BOOL coInit = CoInitialize(nullptr);
HRCHECK(CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory)));
HRCHECK(factory->CreateStream(&stream));
HRCHECK(stream->InitializeFromFilename(filePath, GENERIC_WRITE));
HRCHECK(factory->CreateEncoder(format, nullptr, &encoder));
HRCHECK(encoder->Initialize(stream, WICBitmapEncoderNoCache));
HRCHECK(encoder->CreateNewFrame(&frame, nullptr)); // we don't use options here
HRCHECK(frame->Initialize(nullptr)); // we dont' use any options here
HRCHECK(frame->SetSize(width, height));
HRCHECK(frame->SetPixelFormat(&pf));
HRCHECK(frame->WritePixels(height, stride, stride * height, pixels));
HRCHECK(frame->Commit());
HRCHECK(encoder->Commit());
cleanup:
RELEASE(stream);
RELEASE(frame);
RELEASE(encoder);
RELEASE(factory);
if (coInit) CoUninitialize();
return hr;
}
HRESULT Direct3D9TakeScreenshots(UINT adapter, UINT count)
{
HRESULT hr = S_OK;
IDirect3D9 *d3d = nullptr;
IDirect3DDevice9 *device = nullptr;
IDirect3DSurface9 *surface = nullptr;
D3DPRESENT_PARAMETERS parameters = { 0 };
D3DDISPLAYMODE mode;
D3DLOCKED_RECT rc;
UINT pitch;
SYSTEMTIME st;
LPBYTE *shots = nullptr;
// init D3D and get screen size
d3d = Direct3DCreate9(D3D_SDK_VERSION);
HRCHECK(d3d->GetAdapterDisplayMode(adapter, &mode));
parameters.Windowed = TRUE;
parameters.BackBufferCount = 1;
parameters.BackBufferHeight = mode.Height;
parameters.BackBufferWidth = mode.Width;
parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
parameters.hDeviceWindow = NULL;
// create device & capture surface
HRCHECK(d3d->CreateDevice(adapter, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, ¶meters, &device));
HRCHECK(device->CreateOffscreenPlainSurface(mode.Width, mode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, nullptr));
// compute the required buffer size
HRCHECK(surface->LockRect(&rc, NULL, 0));
pitch = rc.Pitch;
HRCHECK(surface->UnlockRect());
// allocate screenshots buffers
shots = new LPBYTE[count];
for (UINT i = 0; i < count; i++)
{
shots[i] = new BYTE[pitch * mode.Height];
}
GetSystemTime(&st); // measure the time we spend doing <count> captures
wprintf(L"%i:%i:%i.%i\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
for (UINT i = 0; i < count; i++)
{
// get the data
HRCHECK(device->GetFrontBufferData(0, surface));
// copy it into our buffers
HRCHECK(surface->LockRect(&rc, NULL, 0));
CopyMemory(shots[i], rc.pBits, rc.Pitch * mode.Height);
HRCHECK(surface->UnlockRect());
}
GetSystemTime(&st);
wprintf(L"%i:%i:%i.%i\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
// save all screenshots
for (UINT i = 0; i < count; i++)
{
WCHAR file[100];
wsprintf(file, L"cap%i.png", i);
HRCHECK(SavePixelsToFile32bppPBGRA(mode.Width, mode.Height, pitch, shots[i], file, GUID_ContainerFormatPng));
}
cleanup:
if (shots != nullptr)
{
for (UINT i = 0; i < count; i++)
{
delete shots[i];
}
delete[] shots;
}
RELEASE(surface);
RELEASE(device);
RELEASE(d3d);
return hr;
}
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = Direct3D9TakeScreenshots(D3DADAPTER_DEFAULT, 10);
return 0;
}
Gives error at:
// save all screenshots
for (UINT i = 0; i < count; i++)
{
WCHAR file[100];
wsprintf(file, L"cap%i.png", i);
HRCHECK(SavePixelsToFile32bppPBGRA(mode.Width, mode.Height, pitch, shots[i], file, GUID_ContainerFormatPng));
}
Where:
"WCHAR file[100]" is not compatible with "LSPTR" on wsprintf.
L"cap%i.png" (const wchar_t) is not compatible with LPCSTR on wsprintf.
And in:
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = Direct3D9TakeScreenshots(D3DADAPTER_DEFAULT, 10);
return 0;
}
Where _TCHAR is not defined.
¡I'm new to C++ so please give me some hints!
Related
I am learning how to write Linux Device Driver.
I wrote a dummy character device driver, implemented open, release, write, read in fops;
When I read from device , everything was ok;
When I wrote to device by "echo xx > ", the OS was hang.
Even I comment out all codes in write function except pr_alert and return statements, It still hangs;
Could anybody help me figure it out?
#include <linux/init.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/string.h>
struct hello_dev
{
char *buffer;
int length;
dev_t dev;
struct mutex lock;
struct cdev *pcdev;
};
struct hello_dev *pHelloDev;
int open_device(struct inode *pinode, struct file *filp)
{
filp->private_data = pHelloDev;
return 0;
}
int close_device(struct inode *pinode, struct file *filp)
{
struct hello_dev *pDev = filp->private_data;
if (pDev->buffer != NULL)
kfree(pDev->buffer);
pDev->buffer = NULL;
return 0;
}
ssize_t read_device(struct file *filp, char __user *buffer, size_t len, loff_t *loff)
{
pr_alert("read\n");
struct hello_dev *pDev = filp->private_data;
mutex_lock(&pDev->lock);
if (pDev->buffer == NULL)
{
mutex_unlock(&pDev->lock);
return 0;
}
int length = strlen(pDev->buffer);
// offset max than strlen in buffer, return
if (*loff > (length - 1))
{
mutex_unlock(&pDev->lock);
return 0;
} else {
// available to read
int len2read = length - *loff;
if (len < len2read)
{// buffer length less than available data
len2read = len;
}
int read = copy_to_user(buffer, pDev->buffer + *loff, len2read);
if (read)
{
*loff = *loff + read;
mutex_unlock(&pDev->lock);
return read;
} else {
*loff = *loff + len2read;
mutex_unlock(&pDev->lock);
return len2read;
}
}
}
ssize_t write_device(struct file *filp , const char __user *buffer, size_t len, loff_t* loff) {
pr_alert("write %s\n", buffer);
// struct hello_dev *pDev = filp->private_data;
// mutex_lock(&pDev->lock);
// if(pDev->buffer == NULL) {
// pDev->buffer = kmalloc(100, GFP_KERNEL);
// pDev->length = 100;
// }
// copy_from_user(pDev->buffer, buffer, len);
// *loff = *loff + len;
// mutex_unlock(&pDev->lock);
return len;
}
struct file_operations fops = {
.open = open_device,
.release = close_device,
.read = read_device,
.write = write_device
};
int init_device(void)
{
pr_alert("init device\n");
pHelloDev = kmalloc(sizeof(struct hello_dev), GFP_KERNEL);
pHelloDev->buffer = NULL;
pHelloDev->length = 0;
int ret = alloc_chrdev_region(&pHelloDev->dev, 0, 1, "hello");
if (ret)
goto alloc_error;
if (pHelloDev == NULL)
goto kmalloc_error;
pHelloDev->pcdev = cdev_alloc();
pHelloDev->pcdev->ops = &fops;
mutex_init(&pHelloDev->lock);
ret = cdev_add(pHelloDev->pcdev, pHelloDev->dev, 1);
if (ret)
goto cdev_add_error;
return 0;
alloc_error:
pr_alert("alloc_chrdev_region error, %d\n", ret);
return ret;
kmalloc_error:
pr_alert("alloc struct hello_dev error");
return -ENOMEM;
cdev_add_error:
pr_alert("cdev_add error, %d\n", ret);
return ret;
}
void cleanup_device(void)
{
pr_alert("unload ko\n");
cdev_del(pHelloDev->pcdev);
unregister_chrdev_region(pHelloDev->dev, 1);
}
MODULE_LICENSE("GPL");
module_init(init_device);
module_exit(cleanup_device);
I found why write to device hangs.
//this statements has problem
//maybe there is no \0 in buffer
//so I print it out, it will hang
//I wrote a program to write something to device
//and used strace to trace system call made by this program
//and found it hangs at write(...) system call
//and there was nothing printed out
//so, it must be this statement causing the problem
//when I removed this statement, everything was ok
pr_alert("write %s\n", buffer);
I am trying to do Socket programming. I've google and looked at problems like mine. However, I can't see to figure out my error.
Whenever I run my code, I get an error in connect() in main in client.c. The error is invalid argument.
Server.c
/* chatroom server */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <pthread.h>
#include <signal.h>
#define MAX_ROOMS 36
#define MAX_NAME_SIZE 56
#define PORT_NUM 12333
#define MSG_SIZE 8
#define MAX_LOAD 246
#define MAX_CRC 64 //max clients
#define MAX_BUF 256
#define SERVER_IP 32
#define DEBUG 0
struct msg {
int type; //create, join, delete
int length; // length or port num
};
struct chat_room {
int socket_d; //socket descriptor
int port;
pthread_t id; //id of chatroom
char name[MAX_NAME_SIZE];
int clients[MAX_ROOMS]; // used to hold the client's master sockets
};
struct chat_room* findRoom(char* name, struct chat_room* chat){
int iterator;
for(iterator = 0; iterator < MAX_ROOMS; iterator++){
if(strcmp(name, chat[iterator].name) && (chat[iterator].port != 0)) {
return &chat[iterator];
}
}
//if room does not exist
return NULL;
}
struct chat_room* joinServer(int chat_socket, char* name, struct chat_room* chat){
struct chat_room* local_chat = findRoom(name, chat);
int i;
if(local_chat != NULL){ //if the chat exists
for(i= 0; i< MAX_CRC; i++){
if(local_chat->clients[i] == 0)
{
local_chat->clients[i] = chat_socket;
}
return local_chat;
}
}
//if server if full or else error
return NULL;
}
int createResponse(int chat_socket, int new_port_num, int type){
struct msg temp;
char temp_buff[MAX_LOAD];
memset(temp_buff, 0, MAX_LOAD);
temp.type = type;
temp.length = new_port_num;
memcpy(temp_buff, &temp, sizeof(temp));
write(chat_socket, temp_buff, MSG_SIZE);
return 0;
}
int joinResponse(int chat_socket, int new_port_num){
struct msg temp;
char temp_buff[MAX_LOAD];
memset(temp_buff, 0, MAX_LOAD);
temp.type = 11;
temp.length = new_port_num;
memcpy(temp_buff, &temp, sizeof(temp));
write(chat_socket, temp_buff, MSG_SIZE);
return 0;
}
int deleteResponse(int chat_socket, struct chat_room* chat){
struct msg temp;
char temp_buff[MAX_LOAD];
int i;
memset(temp_buff, 0, MAX_LOAD);
temp.type = 12;
memcpy(temp_buff, &temp, sizeof(temp));
for(i=0; i<MAX_CRC; i++){
if((chat->clients[i] != chat_socket) && (chat->clients[i] != 0))
write(chat->clients[i],temp_buff, MSG_SIZE);
}
return 0;
}
struct chat_room* addRoom(int chat_socket, char* name, struct chat_room* chat){
int socket_d;
int i;
struct sockaddr_in sock;
static int port = PORT_NUM;
memset(&sock, 0, sizeof(sock));
int temp = -1;
for(i = 0; i<MAX_ROOMS; i++){
if((strcmp(chat[i].name, name) == 0) && (chat[i].port != 0)){
createResponse(chat_socket, chat[i].port, 15);
return NULL;
}
else if((chat[i].port == 0) && (temp== -1)){
temp = i;
}
}
if(temp == -1){
return NULL;
}
socket_d = socket(AF_INET, SOCK_STREAM, 0);
if(socket_d == -1 && DEBUG){
perror("Error creating chatroom socket");
return NULL;
}
sock.sin_family = AF_INET;
port++;
sock.sin_port = htons(port);
if(bind(socket_d, (struct sockaddr*)&sock, sizeof(struct sockaddr_in)) == -1){
perror("error in binding ");
return NULL;
}
chat[temp].socket_d = socket_d;
chat[temp].port = port;
strcpy(chat[temp].name, name);
return &chat[temp];
}
void* chat_room_main(void* chat_room_cluster){
char buf[MAX_LOAD];
int socket_d, chat_socket;
int temp; //temp_fd
int read_val;
int num_clients = 0;
int i;
int clients[MAX_CRC];
fd_set allfd, modfd;
struct chat_room chat_room_para;
memcpy(&chat_room_para, (struct chat_room*)chat_room_cluster, sizeof(struct chat_room));
free(chat_room_cluster);
memset(clients, 0, sizeof(int)*MAX_CRC);
socket_d = chat_room_para.socket_d;
listen(socket_d, 1);
FD_ZERO(&allfd);
FD_SET(socket_d, &allfd);
printf("New Chatroom Started\n");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++){
if(FD_ISSET(temp, &modfd)){
memset(buf, 0, sizeof(buf));
if(temp == socket_d) {
chat_socket = accept(socket_d, NULL, NULL);
FD_SET(chat_socket, &allfd);
// find an empty spot to add the chat room
for(i = 0; i<MAX_CRC; i++) {
if(clients[i] == 0){
clients[i] = chat_socket;
break;
}
}
sprintf(buf, "Number of people in chatroom: %d", num_clients);
write(chat_socket, buf, strlen(buf));
num_clients++;
}
else{
if(read_val = read(temp, buf, MAX_LOAD) > 0){
for(i = 0; i< MAX_CRC; i++){
if((clients[i] != temp) && (clients[i] != 0)){
write(clients[i], buf, read_val);
}
}
}
else if(read_val <= 0) {
FD_CLR(temp, &allfd);
for(i = 0; i<MAX_CRC; i++){
if(clients[i] == temp)
clients[i] = 0;
}
num_clients--;
close(chat_socket);
}
}
}
}
}
}
int main(int argc, char* argv[]){
int server_socket, chat_socket; //file descriptors for server and chat
int temp; //tempfd
int i, j;
char server_ip[SERVER_IP];
char buf[MAX_BUF];
char msg_buf[MSG_SIZE];
fd_set allfd, modfd;
struct sockaddr_in sock;
struct hostent* host_name;
struct chat_room chatrooms[MAX_ROOMS];
memset(chatrooms, '\0', sizeof(struct chat_room)* MAX_ROOMS);
memset(&sock, '\0', sizeof(sock));
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if(server_socket == -1){
perror("Error creating socket");
return -1;
}
sock.sin_family = AF_INET;
sock.sin_port = htons(PORT_NUM);
sock.sin_addr.s_addr = INADDR_ANY;
if((bind(server_socket, (struct sockaddr*)&sock, sizeof(struct sockaddr_in))) == -1){
perror("Error in bind()");
return -1;
}
listen(server_socket, 1);
FD_ZERO(&allfd);
FD_SET(server_socket, &allfd);
FD_SET(0, &allfd);
printf("\n*******Chatroom Server*******");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++) {
if(FD_ISSET(temp, &modfd)) {
switch(temp){
case 0:
break;
default:
if(temp == server_socket){
chat_socket = accept(server_socket, NULL, NULL);
}
else{
char msg_buf[MSG_SIZE];
char buf[MAX_LOAD];
char name[MAX_LOAD];
struct msg temp_message;
struct chat_room* local_chat = NULL;
void* (*init_chatroom)() = &chat_room_main;
void* thread_args;
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
memset(buf, 0, sizeof(buf));
memset(msg_buf, 0, sizeof(msg_buf));
msg_buf[19]= 0;
int read_val = read(temp, msg_buf, MSG_SIZE);
if(read_val > 0){
memcpy(&temp_message, msg_buf, sizeof(temp_message));
read(temp, buf, temp_message.length - sizeof(temp_message));
memcpy(name, buf, temp_message.length - sizeof(temp_message));
if(temp_message.type == 0) {//if create
local_chat = addRoom(temp, name, chatrooms);
if(local_chat != NULL){
thread_args = (void*)malloc(sizeof(struct chat_room));
memcpy((struct chat_room*) thread_args, local_chat, sizeof(struct chat_room));
pthread_create(&tid, &attr, init_chatroom, thread_args);
local_chat->id = tid;
createResponse(temp, local_chat->port, 10);
}
}
else if(temp_message.type == 1){ //join
local_chat = joinServer(temp, name, chatrooms);
if(local_chat != NULL){
joinResponse(temp, local_chat->port);
}
}
else if(temp_message.type == 2){ //delete
local_chat = findRoom(name, chatrooms);
printf("Deleting Room\n");
if(local_chat != NULL) {
local_chat->port = 0;
close(local_chat->socket_d);
deleteResponse(temp, local_chat);
for(j = 0; j<MAX_CRC; j++){
if(local_chat->clients[j]!=0) {
FD_CLR(local_chat->clients[j], &modfd);
local_chat->clients[j] = 0;
}
}
pthread_cancel(local_chat->id);
}
}
}
else if(read_val <= 0){
FD_CLR(temp, &allfd);
close(temp);
}
}
}
}
}
}
return 0;
}
Client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <pthread.h>
#define PORT_NUM 12333
#define MSG_SIZE 8
#define MAX_LOAD 246
#define MAX_BUF 256
#define SERVER_IP 32
struct msg {
int type;
int length;
};
struct thread_para {
int port;
struct hostent* host_name;
};
int sendCmd(int chat_socket, char* buf, int type){ //function for sending the command
struct msg temp;
char temp_buf[MAX_LOAD];
char name[MAX_LOAD];
int iterator;
if(type == 0){
iterator = 6;
}
else if(type == 1){
iterator = 4;
}
else if(type == 2){
iterator = 6;
}
for(; iterator < strlen(buf); iterator++){
if(buf[iterator] == ' ') {
continue;
}
else{
break;
}
}
strcpy(name, buf+iterator);
memset(temp_buf, 0, MAX_LOAD);
temp.type = type;
temp.length = sizeof(temp)+strlen(name)+1; //for \0
memcpy(temp_buf, &temp, sizeof(temp));
memcpy(temp_buf+sizeof(temp), name, strlen(name)+1);
write(chat_socket, temp_buf, temp.length);
return 0;
}
void* connectChat(int port_num, struct hostent* host_name, int master){
char buf[MAX_BUF];
char temp_buf[MAX_BUF];
int chat_socket;
int i;
int input;
int temp; //temp fd
fd_set allfd, modfd;
struct sockaddr_in sock;
printf("Successfully Joined Room\n");
memset(buf, 0, sizeof(buf));
memset(&sock, 0, sizeof(sock));
sock.sin_family = AF_INET;
sock.sin_port = htons(port_num);
memcpy((char*)&sock.sin_addr.s_addr, host_name->h_addr, host_name->h_length);
chat_socket = socket(AF_INET, SOCK_STREAM, 0);
if(chat_socket == -1){
perror("Error in creation");
return NULL;
}
if(connect(chat_socket, (struct sockaddr*)&sock, sizeof(struct sockaddr)) < 0 ){
perror("Error in connection");
return NULL;
}
FD_ZERO(&allfd);
FD_SET(chat_socket, &allfd);
FD_SET(0, &allfd);
FD_SET(master, &allfd);
while(1) {
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp< FD_SETSIZE; temp++){
memset(buf, 0, sizeof(buf));
memset(temp, 0, sizeof(buf));
if(temp == 0) { //reading from standard in
input = read(0, buf, MAX_BUF);
buf[input-1] = '\0'; //add termination to end
write(chat_socket, buf, strlen(buf));
}
else if(temp == chat_socket){
input = read(0, buf, MAX_BUF);
buf[input] = '\0';
memcpy(temp, buf, input);
//display message
printf("%s \n", temp_buf);
}
else if(temp == master){
struct msg temp_message;
input = read(temp, buf, MSG_SIZE);
memcpy(&temp_message, buf, MSG_SIZE);
if(temp_message.type == 12){
printf("Chatroom has been deleted, Shutting down chatroom\n");
return NULL;
}
}
}
}
return 0;
}
int main(int argc, char* argv[]){
char buf[MAX_BUF];
int chat_socket;
int i;
int input;
int temp; //temp fd
int accept_input = 1; // take input for stdin to create a chat thread
fd_set allfd, modfd;
char server_ip[SERVER_IP];
struct hostent* host_name;
struct sockaddr_in sock;
struct msg temp_message;
pthread_attr_t tattr;
pthread_t tid;
if(argc < 2) {
printf("Please try ./crc <server IP> \n");
return -1;
}
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
memset(&sock, '\0', sizeof(sock));
sock.sin_family = AF_INET;
sock.sin_port = htons(PORT_NUM);
strcpy(server_ip ,argv[1]);
if((host_name = (struct hostent*)gethostbyname(server_ip)) == NULL){
perror("failed to get host name");
return -1;
}
memcpy((char*)&sock.sin_addr.s_addr, host_name->h_addr, host_name->h_length);
chat_socket = socket(AF_INET, SOCK_STREAM, 0);
if(chat_socket == -1){
perror("Error creating socket");
return -1;
}
if((connect(chat_socket, (struct sockaddr*)&sock, sizeof(sock))) < 0) {
perror("Error connecting");
return -1;
}
FD_ZERO(&allfd); /* first, clear the allfd set */
FD_SET(chat_socket, &allfd); /* adding client to the set */
FD_SET(0, &allfd);
printf("*****Welcome to the Chatroom*****\n");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++){
if(FD_ISSET(temp, &modfd)){
if(temp == 0){
input = read(0, buf, MAX_BUF);
buf[input-1] = '\0'; //remove \n inserts termination
if((strncasecmp(buf, "create ", 7) == 0)) {
sendCmd(chat_socket, buf, 0);
}
else if((strncasecmp(buf, "join ", 5) == 0)) {
sendCmd(chat_socket, buf, 1);
}
else if((strncasecmp(buf, "delete ", 7)==0)){
sendCmd(chat_socket, buf, 2);
}
else
{
printf("Enter a valid command: create <Room_name>, join <Room_name>, delete <Room_name>\n");
}
}
else if(temp == chat_socket){
input = read(temp, buf, MSG_SIZE);
memcpy(&temp_message, buf, sizeof(temp_message));
if(temp_message.type == 10) {
printf("Created Chatroom\n");
}
else if(temp_message.type == 11){
connectChat(temp_message.length, host_name, chat_socket);
fflush(stdin);
}
else if(temp_message.type == 15) {
printf("Chatroom exits. Type join <Room_name> to join\n");
}
}
}
}
}
close(chat_socket);
return 0;
}
I gave both sets of code just in case it was need. The program is designed to create multiple chat rooms.
invalid argument is the EINVAL error code, which in the context of connect() means:
An invalid argument was detected (e.g., address_len is not valid for the address family, the specified address family is invalid).
You have multiple calls to connect() in your client code (why?), but you did not indicate which call is the one that is failing. In connectChat() at least, sizeof(struct sockaddr) should be sizeof(struct sockaddr_in) instead, or better sizeof(sock), like you do in main().
Also, if either connect() fails, you are leaking the socket returned by socket(). You need to close() it.
Also, gethostbyname() is deprecated, you should be using getaddrinfo() instead. You are creating IPv4 sockets, which only work with IPv4 addresses. You are not checking if gethostbyname() actually returns an IPv4 address (host_name->h_addr_type == AF_INET) before copying the address bytes into your sock variable. At least with getaddrinfo(), you can restrict the output to IPv4 addresses only. You don't have that option with gethostbyname().
Since you're looking for a way to figure out your error, I'll suggest you to use the following Makefile:
CFLAGS=-Wall -g -O2
CC=gcc
LDFLAGS=-lpthread
all: Server Client
Server: Server.c
Client: Client.c
After running make command you'll see a lot of warnings. Some of them:
Server.c: In function ‘createResponse’:
Server.c:81:5: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
write(chat_socket, temp_buff, MSG_SIZE);
^
Server.c: In function ‘chat_room_main’:
Server.c:237:25: warning: ‘chat_socket’ may be used uninitialized in this function [-Wmaybe-uninitialized]
close(chat_socket);
^
Server.c: In function ‘main’:
Server.c:319:36: warning: array subscript is above array bounds [-Warray-bounds]
msg_buf[19]= 0;
Client.c: In function ‘connectChat’:
Client.c:113:20: warning: passing argument 1 of ‘memset’ makes pointer from integer without a cast
memset(temp, 0, sizeof(buf));
^
So just try to fix these warnings. I mean all of them.
I'm attempting to use the ffmpeg libraries to send a video stream from my application to a media server (in this case wowza). I have been able to do the reverse and consume an RTSP stream but I'm having a few issues writing an RTSP stream.
I have found a few examples and attempted to utilise the relevant bits. The code is below. I have simplified it as much as I can. I do only want to send a single H264 bit stream to the wowza server and which it can handle.
I get an "Integer division by zero" exception whenever in the av_interleaved_write_frame function when I try and send a packet. The exception looks like it's related to the packet timestamps not being set correctly. I've tried different values and can get past the exception by setting some contrived values but then the write call fails.
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>
#include "stdafx.h"
#include "windows.h"
extern "C"
{
#include <libavcodec\avcodec.h>
#include <libavformat\avformat.h>
#include <libavformat\avio.h>
#include <libswscale\swscale.h>
}
using namespace std;
static int video_is_eof;
#define STREAM_DURATION 50.0
#define STREAM_FRAME_RATE 25 /* 25 images/s */
#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
#define VIDEO_CODEC_ID CODEC_ID_H264
static int sws_flags = SWS_BICUBIC;
/* video output */
static AVFrame *frame;
static AVPicture src_picture, dst_picture;
static int frame_count;
static int write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
{
/* rescale output packet timestamp values from codec to stream timebase */
pkt->pts = av_rescale_q_rnd(pkt->pts, *time_base, st->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
pkt->dts = av_rescale_q_rnd(pkt->dts, *time_base, st->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
pkt->duration = av_rescale_q(pkt->duration, *time_base, st->time_base);
pkt->stream_index = st->index;
// Exception occurs here.
return av_interleaved_write_frame(fmt_ctx, pkt);
}
/* Add an output stream. */
static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id)
{
AVCodecContext *c;
AVStream *st;
/* find the encoder */
*codec = avcodec_find_encoder(codec_id);
if (!(*codec)) {
fprintf(stderr, "Could not find encoder for '%s'\n", avcodec_get_name(codec_id));
exit(1);
}
st = avformat_new_stream(oc, *codec);
if (!st) {
fprintf(stderr, "Could not allocate stream\n");
exit(1);
}
st->id = oc->nb_streams - 1;
c = st->codec;
c->codec_id = codec_id;
c->bit_rate = 400000;
c->width = 352;
c->height = 288;
c->time_base.den = STREAM_FRAME_RATE;
c->time_base.num = 1;
c->gop_size = 12; /* emit one intra frame every twelve frames at most */
c->pix_fmt = STREAM_PIX_FMT;
return st;
}
static void open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st)
{
int ret;
AVCodecContext *c = st->codec;
/* open the codec */
ret = avcodec_open2(c, codec, NULL);
if (ret < 0) {
fprintf(stderr, "Could not open video codec: ");
exit(1);
}
/* allocate and init a re-usable frame */
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
/* Allocate the encoded raw picture. */
ret = avpicture_alloc(&dst_picture, c->pix_fmt, c->width, c->height);
if (ret < 0) {
fprintf(stderr, "Could not allocate picture: ");
exit(1);
}
/* copy data and linesize picture pointers to frame */
*((AVPicture *)frame) = dst_picture;
}
/* Prepare a dummy image. */
static void fill_yuv_image(AVPicture *pict, int frame_index, int width, int height)
{
int x, y, i;
i = frame_index;
/* Y */
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
/* Cb and Cr */
for (y = 0; y < height / 2; y++) {
for (x = 0; x < width / 2; x++) {
pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
}
}
}
static void write_video_frame(AVFormatContext *oc, AVStream *st, int flush)
{
int ret;
AVCodecContext *c = st->codec;
if (!flush) {
fill_yuv_image(&dst_picture, frame_count, c->width, c->height);
}
AVPacket pkt = { 0 };
int got_packet;
av_init_packet(&pkt);
/* encode the image */
frame->pts = frame_count;
ret = avcodec_encode_video2(c, &pkt, flush ? NULL : frame, &got_packet);
if (ret < 0) {
fprintf(stderr, "Error encoding video frame:");
exit(1);
}
/* If size is zero, it means the image was buffered. */
if (got_packet) {
ret = write_frame(oc, &c->time_base, st, &pkt);
}
else {
if (flush) {
video_is_eof = 1;
}
ret = 0;
}
if (ret < 0) {
fprintf(stderr, "Error while writing video frame: ");
exit(1);
}
frame_count++;
}
static void close_video(AVFormatContext *oc, AVStream *st)
{
avcodec_close(st->codec);
av_free(src_picture.data[0]);
av_free(dst_picture.data[0]);
av_frame_free(&frame);
}
int _tmain(int argc, _TCHAR* argv[])
{
printf("starting...\n");
const char *filename = "rtsp://test:password#192.168.33.19:1935/ffmpeg/0";
AVOutputFormat *fmt;
AVFormatContext *oc;
AVStream *video_st;
AVCodec *video_codec;
double video_time;
int flush, ret;
/* Initialize libavcodec, and register all codecs and formats. */
av_register_all();
avformat_network_init();
AVOutputFormat* oFmt = av_oformat_next(NULL);
while (oFmt) {
if (oFmt->video_codec == VIDEO_CODEC_ID) {
break;
}
oFmt = av_oformat_next(oFmt);
}
if (!oFmt) {
printf("Could not find the required output format.\n");
exit(1);
}
/* allocate the output media context */
avformat_alloc_output_context2(&oc, oFmt, "rtsp", filename);
if (!oc) {
printf("Could not set the output media context.\n");
exit(1);
}
fmt = oc->oformat;
if (!fmt) {
printf("Could not create the output format.\n");
exit(1);
}
video_st = NULL;
cout << "Codec = " << avcodec_get_name(fmt->video_codec) << endl;
if (fmt->video_codec != AV_CODEC_ID_NONE)
{
video_st = add_stream(oc, &video_codec, fmt->video_codec);
}
/* Now that all the parameters are set, we can open the video codec and allocate the necessary encode buffers. */
if (video_st) {
open_video(oc, video_codec, video_st);
}
av_dump_format(oc, 0, filename, 1);
char errorBuff[80];
if (!(fmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open outfile '%s': %s", filename, av_make_error_string(errorBuff, 80, ret));
return 1;
}
}
flush = 0;
while (video_st && !video_is_eof) {
/* Compute current video time. */
video_time = (video_st && !video_is_eof) ? video_st->pts.val * av_q2d(video_st->time_base) : INFINITY;
if (!flush && (!video_st || video_time >= STREAM_DURATION)) {
flush = 1;
}
if (video_st && !video_is_eof) {
write_video_frame(oc, video_st, flush);
}
}
if (video_st) {
close_video(oc, video_st);
}
if ((fmt->flags & AVFMT_NOFILE)) {
avio_close(oc->pb);
}
avformat_free_context(oc);
printf("finished.\n");
getchar();
return 0;
}
Does anyone have any insights about how the packet timestamps can be successfully set?
I solved the integer division by zero by building ffmpeg on my Windows instance and debugging the av_interleaved_write_frame call. Turns out it was the pts not being set on the video stream object that was causing the exception.
Adding the line below to the while loop in the main function fixed the problem:
video_st->pts.val += av_rescale_q(1, video_st->codec->time_base, video_st->time_base);
Here's a sample that works to get a H264 encoded dummy stream to a Wowza server via ffmpeg's RTSP pipeline.
// Roughly based on: https://ffmpeg.org/doxygen/trunk/muxing_8c-source.html
#include <chrono>
#include <thread>
#include <tchar.h>
extern "C"
{
#include <libavcodec\avcodec.h>
#include <libavformat\avformat.h>
#include <libavformat\avio.h>
#include <libswscale\swscale.h>
#include <libavutil\time.h>
}
#pragma comment(lib,"libavformat/libavformat.a")
#pragma comment(lib,"libavcodec/libavcodec.a")
#pragma comment(lib,"libavutil/libavutil.a")
#pragma comment(lib,"libswscale/libswscale.a")
#pragma comment(lib,"x264.lib")
#pragma comment(lib,"libswresample/libswresample.a")
using namespace std;
static int video_is_eof;
#define STREAM_DURATION 20
#define STREAM_FRAME_RATE 25 /* 25 images/s */
#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */ //AV_PIX_FMT_NV12;
#define VIDEO_CODEC_ID CODEC_ID_H264
/* video output */
static AVFrame *frame;
static AVPicture src_picture, dst_picture;
/* Add an output stream. */
static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id)
{
AVCodecContext *c;
AVStream *st;
/* find the encoder */
*codec = avcodec_find_encoder(codec_id);
if (!(*codec)) {
av_log(NULL, AV_LOG_ERROR, "Could not find encoder for '%s'.\n", avcodec_get_name(codec_id));
}
else {
st = avformat_new_stream(oc, *codec);
if (!st) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate stream.\n");
}
else {
st->id = oc->nb_streams - 1;
st->time_base.den = st->pts.den = 90000;
st->time_base.num = st->pts.num = 1;
c = st->codec;
c->codec_id = codec_id;
c->bit_rate = 400000;
c->width = 352;
c->height = 288;
c->time_base.den = STREAM_FRAME_RATE;
c->time_base.num = 1;
c->gop_size = 12; /* emit one intra frame every twelve frames at most */
c->pix_fmt = STREAM_PIX_FMT;
}
}
return st;
}
static int open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st)
{
int ret;
AVCodecContext *c = st->codec;
/* open the codec */
ret = avcodec_open2(c, codec, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not open video codec.\n", avcodec_get_name(c->codec_id));
}
else {
/* allocate and init a re-usable frame */
frame = av_frame_alloc();
if (!frame) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate video frame.\n");
ret = -1;
}
else {
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
/* Allocate the encoded raw picture. */
ret = avpicture_alloc(&dst_picture, c->pix_fmt, c->width, c->height);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate picture.\n");
}
else {
/* copy data and linesize picture pointers to frame */
*((AVPicture *)frame) = dst_picture;
}
}
}
return ret;
}
/* Prepare a dummy image. */
static void fill_yuv_image(AVPicture *pict, int frame_index, int width, int height)
{
int x, y, i;
i = frame_index;
/* Y */
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
/* Cb and Cr */
for (y = 0; y < height / 2; y++) {
for (x = 0; x < width / 2; x++) {
pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
}
}
}
static int write_video_frame(AVFormatContext *oc, AVStream *st, int frameCount)
{
int ret = 0;
AVCodecContext *c = st->codec;
fill_yuv_image(&dst_picture, frameCount, c->width, c->height);
AVPacket pkt = { 0 };
int got_packet;
av_init_packet(&pkt);
/* encode the image */
frame->pts = frameCount;
ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error encoding video frame.\n");
}
else {
if (got_packet) {
pkt.stream_index = st->index;
pkt.pts = av_rescale_q_rnd(pkt.pts, c->time_base, st->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
ret = av_write_frame(oc, &pkt);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error while writing video frame.\n");
}
}
}
return ret;
}
int _tmain(int argc, _TCHAR* argv[])
{
printf("starting...\n");
const char *url = "rtsp://test:password#192.168.33.19:1935/ffmpeg/0";
//const char *url = "rtsp://192.168.33.19:1935/ffmpeg/0";
AVFormatContext *outContext;
AVStream *video_st;
AVCodec *video_codec;
int ret = 0, frameCount = 0;
av_log_set_level(AV_LOG_DEBUG);
//av_log_set_level(AV_LOG_TRACE);
av_register_all();
avformat_network_init();
avformat_alloc_output_context2(&outContext, NULL, "rtsp", url);
if (!outContext) {
av_log(NULL, AV_LOG_FATAL, "Could not allocate an output context for '%s'.\n", url);
goto end;
}
if (!outContext->oformat) {
av_log(NULL, AV_LOG_FATAL, "Could not create the output format for '%s'.\n", url);
goto end;
}
video_st = add_stream(outContext, &video_codec, VIDEO_CODEC_ID);
/* Now that all the parameters are set, we can open the video codec and allocate the necessary encode buffers. */
if (video_st) {
av_log(NULL, AV_LOG_DEBUG, "Video stream codec %s.\n ", avcodec_get_name(video_st->codec->codec_id));
ret = open_video(outContext, video_codec, video_st);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Open video stream failed.\n");
goto end;
}
}
else {
av_log(NULL, AV_LOG_FATAL, "Add video stream for the codec '%s' failed.\n", avcodec_get_name(VIDEO_CODEC_ID));
goto end;
}
av_dump_format(outContext, 0, url, 1);
ret = avformat_write_header(outContext, NULL);
if (ret != 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to connect to RTSP server for '%s'.\n", url);
goto end;
}
printf("Press any key to start streaming...\n");
getchar();
auto startSend = std::chrono::system_clock::now();
while (video_st) {
frameCount++;
auto startFrame = std::chrono::system_clock::now();
ret = write_video_frame(outContext, video_st, frameCount);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Write video frame failed.\n", url);
goto end;
}
auto streamDuration = std::chrono::duration_cast<chrono::milliseconds>(std::chrono::system_clock::now() - startSend).count();
printf("Elapsed time %ldms, video stream pts %ld.\n", streamDuration, video_st->pts.val);
if (streamDuration / 1000.0 > STREAM_DURATION) {
break;
}
else {
auto frameDuration = std::chrono::duration_cast<chrono::milliseconds>(std::chrono::system_clock::now() - startFrame).count();
std::this_thread::sleep_for(std::chrono::milliseconds((long)(1000.0 / STREAM_FRAME_RATE - frameDuration)));
}
}
if (video_st) {
avcodec_close(video_st->codec);
av_free(src_picture.data[0]);
av_free(dst_picture.data[0]);
av_frame_free(&frame);
}
avformat_free_context(outContext);
end:
printf("finished.\n");
getchar();
return 0;
}
Why? I didn't do anything on the other peer!
I was using massive threads to get data from the server. When the thread count is small, it's ok. But when the thread count is very large, recv() return -1 and errno indicates "Connection reset by peer".
Here is an example to reproduce the issue:
server.cc
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
char buffer[4096];
inline int send_all(int socket_fd, const char* data, size_t size, int flags)
{
int result;
const char* pos = data;
while (size > 0)
{
result = send(socket_fd, pos, size, flags);
assert(result > 0);
pos += result;
size -= result;
}
return 0;
}
inline int recv_all(int socket_fd, void* data, size_t size, int flags)
{
int result = recv(socket_fd, data, size, flags | MSG_WAITALL);
assert(((size_t) result) == size);
return 0;
}
void* server_thread(void* arg)
{
int socket_fd = (int) ((long) arg);
// recv some info first
recv_all(socket_fd, buffer, 1, 0);
// simulate some computation
for (int i = 0; i < 0xffff; i ++)
for (int j = 0; j < 0xffff; j ++);
// send data
for (int i = 0; i < 4096; i ++)
send_all(socket_fd, buffer, sizeof(buffer), 0);
// the peer is closed, return 0
recv(socket_fd, buffer, 1, MSG_WAITALL);
close(socket_fd);
pthread_detach(pthread_self());
return NULL;
}
int main(void)
{
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
assert(listen_socket != -1);
struct sockaddr_in listen_address;
listen_address.sin_family = AF_INET;
listen_address.sin_port = htons(11282);
listen_address.sin_addr.s_addr = INADDR_ANY;
int result = bind(listen_socket,
(struct sockaddr*) &listen_address,
sizeof(listen_address));
assert(result != -1);
result = listen(listen_socket, 5);
assert(result != -1);
while (true)
{
int server_socket = accept(listen_socket, NULL, NULL);
assert(server_socket != -1);
pthread_t tid;
result = pthread_create(&tid,
NULL,
server_thread,
(void *) ((long) server_socket));
assert(result != -1);
}
return 0;
}
client.cc
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
pthread_t threads[4096];
char buffer[4096];
inline int send_all(int socket_fd, const char* data, size_t size, int flags)
{
int result;
const char* pos = data;
while (size > 0)
{
result = send(socket_fd, pos, size, flags);
assert(result > 0);
pos += result;
size -= result;
}
return 0;
}
inline int recv_all(int socket_fd, void* data, size_t size, int flags)
{
int result = recv(socket_fd, data, size, flags | MSG_WAITALL);
assert(((size_t) result) == size);
return 0;
}
void* client_thread(void* arg)
{
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
assert(socket_fd != -1);
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(11282);
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
int result = connect(socket_fd,
(struct sockaddr *) &server_address,
sizeof(server_address));
assert(result != -1);
// send some info first
send_all(socket_fd, buffer, 1, 0);
// recv the reply data
for (int i = 0; i < 4096; i ++)
recv_all(socket_fd, buffer, sizeof(buffer), 0);
close(socket_fd);
return NULL;
}
int main(int argc, char* argv[])
{
assert(argc == 2);
// get client thread count
int thread_count = atoi(argv[1]);
assert(thread_count <= 4096);
for (int i = 0; i < thread_count; i ++)
{
int result = pthread_create(&threads[i], NULL, client_thread, NULL);
assert(result != -1);
}
for (int i = 0; i < thread_count; i ++)
pthread_join(threads[i], NULL);
return 0;
}
Usage:
./server
./client [thread_count]
I was using 480 as the thread_count, sometime I could reproduce the issue.
I'm facing some problems with understanding how the SDL audio callback works.
I have this simple code, which should generate a simple square wave:
#include "SDL.h"
#include "SDL_audio.h"
#include <stdlib.h>
#include <math.h>
SDL_Surface *screen;
SDL_AudioSpec spec;
Uint32 sound_len=512;
Uint8 *sound_buffer;
int sound_pos = 0;
int counter;
unsigned int phase_delta=600;
unsigned int phase;
unsigned char out;
//Initialization
void init_sdl (void)
{
if (SDL_Init (SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0)
exit (-1);
atexit (SDL_Quit);
screen = SDL_SetVideoMode (640, 480, 16, SDL_HWSURFACE);
if (screen == NULL)
exit (-1);
}
//Generates a new sample and outputs it to the audio card
void Callback (void *userdata, Uint8 *stream, int len)
{
Uint8 *waveptr;
//Generates a new sample
phase+=phase_delta;
if ((phase>>8)<127) out=255; else out=0;
//End
//Output the current sample to the audio card
waveptr = sound_buffer;
SDL_MixAudio(stream, waveptr, 1, SDL_MIX_MAXVOLUME);
}
void play (void)
{
sound_buffer = new Uint8[512];
sound_len= 512;
spec.freq = 22050;
spec.format = AUDIO_S16SYS;
spec.channels = 1;
spec.silence = 0;
spec.samples = 512;
spec.padding = 0;
spec.size = 0;
spec.userdata = 0;
spec.callback = Callback;
if (SDL_OpenAudio (&spec, NULL) < 0)
{ //Throw an error
printf ("I don't think you like this: %s\n", SDL_GetError ());
exit (-1);
}
SDL_PauseAudio (0);//Start the audio
}
int main(int argc, char* argv[])
{
init_sdl ();
play ();
SDL_Delay (250);
return 0;
}
I know that the callback is not done right, because I have no idea how to output to the buffer. Each time the callback is called, the first part of the callback function code generates the new sample, and stores it in the variabile Out.
Can anyone here modify this code so that the new samples go from Out to the correct position in the audio buffer?
Also, I don't want to have the code modified in a very super-complex way just to generate the square wave - I have already taken care of that. The wave is generated correctly, each new sample appearing in the variable Out. I just need these samples to be routed correctly to the audio buffer.
You need to cast stream to a actual.format-appropriate datatype and then overwrite the values in stream with len / sizeof( <format's datatype> ) samples.
The square-wave will be kinda hard to hear because the given algorithm will only generate a brief high pulse every ~7.1 million samples (~5 minutes #22050Hz) when phase wraps around.
Try something like this:
#include <SDL.h>
#include <SDL_audio.h>
#include <iostream>
using namespace std;
//Generates new samples and outputs them to the audio card
void Callback( void* userdata, Uint8* stream, int len )
{
// the format of stream depends on actual.format in main()
// we're assuming it's AUDIO_S16SYS
short* samples = reinterpret_cast< short* >( stream );
size_t numSamples = len / sizeof( short );
const unsigned int phase_delta = 600;
static unsigned int phase = 0;
// loop over all our samples
for( size_t i = 0; i < numSamples; ++i )
{
phase+=phase_delta;
short out = 0;
if ((phase>>8)<127) out=SHRT_MAX; else out=0;
samples[i] = out;
}
}
int main( int argc, char* argv[] )
{
if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO ) < 0 )
return -1;
atexit( SDL_Quit );
SDL_Surface* screen = SDL_SetVideoMode( 640, 480, 16, SDL_ANYFORMAT );
if( screen == NULL)
return -1;
SDL_AudioSpec spec;
spec.freq = 22050;
spec.format = AUDIO_S16SYS;
spec.channels = 1;
spec.samples = 4096;
spec.callback = Callback;
spec.userdata = NULL;
SDL_AudioSpec actual;
if( SDL_OpenAudio( &spec, &actual ) < 0 )
{
cerr << "I don't think you like this: " << SDL_GetError() << endl;
return -1;
}
if( spec.format != actual.format )
{
cerr << "format mismatch!" << endl;
return -1;
}
SDL_PauseAudio( 0 );
SDL_Event ev;
while( SDL_WaitEvent( &ev ) )
{
if( ev.type == SDL_QUIT )
break;
}
SDL_CloseAudio();
SDL_Quit();
return 0;
}