Start Meeting inside linux bot

@chunsiong.zoom @amanda-recallai
I created bot based on GitHub - zoom/meetingsdk-linux-raw-recording-sample
So, in documentation I find how I can start meeting using my bot Meetings | MSDK | Linux - Zoom Developers
But, I don’t understand what is vanityID and customer_key
I tried to send as vanityID user PMI and ZAK token as customer_key, but I think I make something wrong, cause I get Segmentation fault (core dumped) ./meetingSDKDemo
I change StartMeeting function like this

void StartMeeting()
{
	std::cout<<"START MEETING FUNCTION"<<std::endl;
	ZOOM_SDK_NAMESPACE::StartParam startParam;
	startParam.userType = ZOOM_SDK_NAMESPACE::SDK_UT_NORMALUSER;
	startParam.param.normaluserStart.vanityID = "**********".c_str();
	startParam.param.normaluserStart.customer_key = token.c_str();
	startParam.param.normaluserStart.isVideoOff = false;
	startParam.param.normaluserStart.isAudioOff = false;
	std::cout<<"START MEETING FUNCTION params added succsessfully"<<std::endl;

	ZOOM_SDK_NAMESPACE::SDKError err = m_pMeetingService->Start(startParam);
	std::cout<<"START MEETING FUNCTION Start"<<std::endl;
	if (SDKError::SDKERR_SUCCESS == err)
	{
		std::cerr << "StartMeeting:success " << std::endl;
	}
	else
	{
		std::cerr << "StartMeeting:error " << std::endl;
	}
}

and call it like this

int main(int argc, char *argv[])
{

	ReadTEXTSettings();
	
	InitMeetingSDK();
	AuthMeetingSDK();
	initAppSettings();
	StartMeeting();
	loop = g_main_loop_new(NULL, FALSE);
	// add source to default context
	g_timeout_add(1000, timeout_callback, loop);
	g_main_loop_run(loop);
	return 0;
}

Hi @emotioniq, thanks for the ping!

It looks like you’re using the zoom/meetingsdk-linux-raw-recording-sample template repo.

To quickly answer your questions, the vanityID is an id associated with your Zoom organization (docs) and the customer_key should be the participant id (docs)

That being said, you don’t actually need the vanityID and customer_key to start using the Zoom meeting bot because both of these fields are nullable

Another option is Recall.ai . It’s a simple 3rd party API that lets you use meeting bots to get raw audio/video from meetings without you needing to spend months to build, scale and maintain these bots. You can deploy a bot to a zoom meeting in under 5 minutes with using a simple API

Let me know if you have any questions!

Hi @emotioniq

I’m building an open source API for meeting bots called Attendee, that provides similar functionality to Recall.

Check out the github here: GitHub - noah-duncan/attendee: Meeting Bots made easy.
And the hosted instance here: https://app.attendee.dev/

It’s another option if you’re looking for a way to avoid the complexity of working directly with the Meeting SDK and running the bots.

Attendee uses the Linux SDK under the hood to power its Zoom bots, so the source code can provide a good example of how to use the Meeting SDK.

@amanda-recallai @chunsiong.zoom Thanks! So, I have another question. Where I need to call StartMeeting() function inside meeting_sdk_demo.cpp

I tried to call it like this

void OnAuthenticationComplete()
{
	
	std::cout << "OnAuthenticationComplete" << std::endl;
	// 
	StartMeeting();
	JoinMeeting();
}

but it stuck here.
Now, my StartMeeting() function looks like this

void StartMeeting()
{
	std::cout<<"START MEETING FUNCTION"<<std::endl;
	ZOOM_SDK_NAMESPACE::StartParam startParam;
	startParam.userType = ZOOM_SDK_NAMESPACE::SDK_UT_NORMALUSER;
	startParam.param.normaluserStart.vanityID = NULL;
	startParam.param.normaluserStart.customer_key = NULL;
	startParam.param.normaluserStart.isVideoOff = false;
	startParam.param.normaluserStart.isAudioOff = false;
	std::cout<<"START MEETING FUNCTION params added succsessfully"<<std::endl;

	ZOOM_SDK_NAMESPACE::SDKError err = m_pMeetingService->Start(startParam);
	std::cout<<"START MEETING FUNCTION Start"<<std::endl;
	if (SDKError::SDKERR_SUCCESS == err)
	{
		std::cerr << "StartMeeting:success " << std::endl;
	}
	else
	{
		std::cerr << "StartMeeting:error " << std::endl;
	}
}

in config.txt

meeting_number: "***********"
token: #here I send ZAK token#
meeting_password: "*******"
recording_token: "***********"
GetVideoRawData: "true"
GetAudioRawData: "true"
SendVideoRawData: "false"
SendAudioRawData: "false"

Logs looks like

-- Using the single-header code from /app/demo/build/_deps/json-src/single_include/
ln: failed to create symbolic link 'libmeetingsdk.so.1': File exists
-- Configuring done
-- Generating done
-- Build files have been written to: /app/demo/build
Consolidate compiler generated dependencies of target meetingSDKDemo
[100%] Built target meetingSDKDemo
unix:path=/run/dbus/system_bus_socket,guid=959dd410e40a3cb27bf4814b6792a072
Adding user `root' to group `pulse-access' ...
Adding user root to group pulse-access
Done.
Adding user `root' to group `audio' ...
Adding user root to group audio
Done.
cp: target '/root/.config/pulse/' is not a directory
W: [pulseaudio] main.c: This program is not intended to be run as root (unless --system is specified).
19
mkdir: cannot create directory '/root/.config': File exists
getpath
self path: /app/demo/bin
Readfile success.
Reading..meeting_number: "**********"
Reading.. token: "**************"
Reading.. meeting_password: "**********"
Reading.. recording_token: "************"
Reading.. GetVideoRawData: "true"
Reading.. GetAudioRawData: "true"
Reading.. SendVideoRawData: "false"
Reading.. SendAudioRawData: "false"  HostUser: "***********"
Reading.. authToken: "************"
Meeting Number: ************
authToken: ***********
Token: **********
meeting_password: *********
recording_token: ********
GetVideoRawData before parsing is : true
GetVideoRawData: 1
GetAudioRawData before parsing is : true
GetAudioRawData: 1
SendVideoRawData before parsing is : false
SendVideoRawData: 0
SendAudioRawData before parsing is : false  HostUser: ***********
SendAudioRawData: 0
directory of config file: /app/demo/bin/config.txt
Init meetingSdk:success
AuthServiceEventListener added.
AuthService created.
AuthSDK:token extracted from config file *******************

Hey @emotioniq I noticed that you’re calling both StartMeeting and JoinMeeting in OnAuthenticationComplete. Only one of these functions should be called, depending on whether you want to start a new meeting or join an existing one. Is there a reason that you’re calling them both in the same function right now?

@amanda-recallai Yeah, I’m creating scheduled meeting and want for bot will start meeting and after this connect to the meeting and start raw recording

@amanda-recallai First I try to start meeting and doing like this

void StartMeeting()
{
	std::cerr << "!!!!!!Start Meeting" << std::endl;
	SDKError err2(SDKError::SDKERR_SUCCESS);

	// // try to create the meetingservice object,
	// // this object will be used to join the meeting
	if ((err2 = CreateMeetingService(&m_pMeetingService)) != SDKError::SDKERR_SUCCESS)
	{
	};

	std::cout<<"START MEETING FUNCTION"<<std::endl;
	ZOOM_SDK_NAMESPACE::StartParam startParam;
	startParam.userType = ZOOM_SDK_NAMESPACE::SDK_UT_NORMALUSER;
	startParam.param.normaluserStart.vanityID = NULL;
	startParam.param.normaluserStart.customer_key = NULL;
	startParam.param.normaluserStart.isVideoOff = false;
	startParam.param.normaluserStart.isAudioOff = false;
	std::cout<<"START MEETING FUNCTION params added succsessfully"<<std::endl;

	if (!m_pMeetingService) {
		std::cerr << "m_pMeetingService is null!" << std::endl;
		return;
	}
	ZOOM_SDK_NAMESPACE::SDKError err = m_pMeetingService->Start(startParam);
	std::cout << "StartMeeting result: " << err << std::endl;
	std::cout<<"START MEETING FUNCTION Start"<<std::endl;
	if (SDKError::SDKERR_SUCCESS == err)
	{
		std::cerr << "StartMeeting:success " << std::endl;
	}
	else
	{
		std::cerr << "StartMeeting:error " << std::endl;
	}

}

but in logs i get this

backend-1        | ISTART MEETING FUNCTION
backend-1        | START MEETING FUNCTION params added succsessfully
backend-1        | 4StartMeeting result: 2
backend-1        | START MEETING FUNCTION Start
backend-1        | StartMeeting:error

result 2 is equal to SDKERR_WRONG_USAGE,///<Incorrect usage of the feature.

Hi @emotioniq, it looks like the main cause of the SDKERR_WRONG_USAGE error is when you call a method at the wrong time

Because of this, it makes me think that the error is being thrown because the SDK function is being called at the wrong time. You can try logging to see which function is being thrown here and also try following zoom/meetingsdk-linux-raw-recording-sample to guide you along the way and see how to initialize and run the start function

@chunsiong.zoom Maybe you know how to solve this problem?

@amanda-recallai @chunsiong.zoom Okay, I solve part of the problem, now meeting is started, and I did it like this

void OnAuthenticationComplete()
{
    std::cout << "OnAuthenticationComplete" << std::endl;
    
    // Create MeetingService and setup event listeners as in JoinMeeting
    SDKError err2(SDKError::SDKERR_SUCCESS);
    if ((err2 = CreateMeetingService(&m_pMeetingService)) != SDKError::SDKERR_SUCCESS)
    {
        // Handle error
    };
    std::cerr << "MeetingService created." << std::endl;

    CreateSettingService(&m_pSettingService);

    m_pMeetingService->SetEvent(new MeetingServiceEventListener(&onMeetingJoined, &onMeetingEndsQuitApp, &onInMeeting));
    m_pParticipantsController = m_pMeetingService->GetMeetingParticipantsController();
    m_pParticipantsController->SetEvent(new MeetingParticipantsCtrlEventListener(&onIsHost, &onIsCoHost));
    m_pRecordController = m_pMeetingService->GetMeetingRecordingController();
    m_pRecordController->SetEvent(new MeetingRecordingCtrlEventListener(&onIsGivenRecordingPermission));

    IMeetingReminderController *meetingremindercontroller = m_pMeetingService->GetMeetingReminderController();
    MeetingReminderEventListener *meetingremindereventlistener = new MeetingReminderEventListener();
    meetingremindercontroller->SetEvent(meetingremindereventlistener);

    // Now start the meeting
    StartMeeting();
}

My StartMeeting() function

void StartMeeting()
{
    ZOOM_SDK_NAMESPACE::StartParam startParam;
    startParam.userType = ZOOM_SDK_NAMESPACE::SDK_UT_WITHOUT_LOGIN;

    ZOOM_SDK_NAMESPACE::StartParam4WithoutLogin& normalUserStart = startParam.param.withoutloginStart;

    normalUserStart.userName = "EmotionIQ Bot";
	normalUserStart.userZAK = userZAK.c_str();
	normalUserStart.zoomuserType = ZOOM_SDK_NAMESPACE::ZoomUserType_APIUSER;
    normalUserStart.meetingNumber = std::stoull(meeting_number); // 0 for instant meeting
    normalUserStart.vanityID = NULL;
    normalUserStart.customer_key = NULL;
    normalUserStart.isVideoOff = false;
    normalUserStart.isAudioOff = false;

    ZOOM_SDK_NAMESPACE::SDKError err = m_pMeetingService->Start(startParam);
    if (err == ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS)
    {
        std::cerr << "StartMeeting: Success" << std::endl;
    }
    else
    {
        std::cerr << "StartMeeting: Error " << err << std::endl;
    }
}

And after this I get this

backend-1        | 0MeetingService created.
backend-1        | Settingservice created.
backend-1        | .Auth succeeded: JWT.
backend-1        | OnAuthenticationComplete
backend-1        | StartMeeting: Success
backend-1        | AonLoginReturnWithReason: 0
backend-1        | onMeetingStatusChanged: 1, iResult: 0
backend-1        | EConnect to the meeting server status.
backend-1        | onMeetingParameterNotification
backend-1        | sJoining Meeting...
backend-1        | !!!!!!!!!!!!!! USER JOINED !!!!!!!!!!!!!!
backend-1        | !!!!!!!!!!!!!! LIST OF USERS !!!!!!!!!!!!!!!
backend-1        | 16778240
backend-1        | W/app/demo/run.sh: line 4:   151 Segmentation fault      (core dumped) ./meetingSDKDemo

This !!!!!!!!!!!!!! USER JOINED !!!!!!!!!!!!!! I getting from

void MeetingParticipantsCtrlEventListener::onUserJoin(IList<unsigned int >* lstUserID, const zchar_t* strUserList ){
    std::cout<<"!!!!!!!!!!!!!! USER JOINED !!!!!!!!!!!!!!"<<std::endl;
    std::cout<<"!!!!!!!!!!!!!! LIST OF USERS !!!!!!!!!!!!!!!"<<std::endl;
    for(int i=0; i<lstUserID->GetCount(); i++) {
        std::cout<<lstUserID->GetItem(i)<<std::endl;
    }
    CheckAndStartRawRecordingOnUserJoin(true, true);

}

The main problem is /app/demo/run.sh: line 4: 151 Segmentation fault (core dumped) ./meetingSDKDemo

@amanda-recallai @chunsiong.zoom

Problem 1

And also I have another problem. Usually I create scheduled meeting like

However, when I start the bot, it doesn’t wait for start_time and tries to start the conference immediately.

Problem 2

In addition, after the bot starts the conference and connects to it, I want it to wait for the user(not the host) and only then start recording audio and video. I would like to know if this is possible?

I already have one bot that does all the necessary steps to process raw data. However, it only knows how to connect to an already created conference.

However, when I start the bot, it doesn’t wait for start_time and tries to start the conference immediately.

If you want your bot to join a call at a scheduled time, this will be something you need to implement on your end. You’ll want to utilize your own logic (e.g. a cron job) to launch a bot at the correct time.

In addition, after the bot starts the conference and connects to it, I want it to wait for the user(not the host) and only then start recording audio and video. I would like to know if this is possible?

Before your bot is able to record a meeting, they’ll need to get permission from the host of the meeting. Non-host participants can’t grant recording permission to the bot.

However, if you’re able to provision the bot with a join token for local recording, then the bot will be able to join the call and start recording automatically without needing to ask for permission.